diff options
author | Akinori Ito <aito@eie.yz.yamagata-u.ac.jp> | 2001-11-08 05:14:08 +0000 |
---|---|---|
committer | Akinori Ito <aito@eie.yz.yamagata-u.ac.jp> | 2001-11-08 05:14:08 +0000 |
commit | 68a07bf03b7624c9924065cce9ffa45497225834 (patch) | |
tree | c2adb06a909a8594445e4a3f8587c4bad46e3ecd /file.c | |
download | w3m-68a07bf03b7624c9924065cce9ffa45497225834.tar.gz w3m-68a07bf03b7624c9924065cce9ffa45497225834.zip |
Initial revision
Diffstat (limited to '')
-rw-r--r-- | file.c | 6002 |
1 files changed, 6002 insertions, 0 deletions
@@ -0,0 +1,6002 @@ +/* $Id: file.c,v 1.1 2001/11/08 05:14:50 a-ito Exp $ */ +#include "fm.h" +#include <sys/types.h> +#include "myctype.h" +#include <signal.h> +#include <setjmp.h> +#include <sys/wait.h> +#include <stdio.h> +#include <time.h> +#ifdef __EMX__ +#include <strings.h> +#endif /* __EMX__ */ +#include <sys/stat.h> +#include <fcntl.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 void gunzip_stream(URLFile * uf); +static FILE *lessopen_stream(char *path); +static Buffer *loadcmdout(char *cmd, + Buffer * (*loadproc) (URLFile *, Buffer *), + Buffer *defaultbuf); +static void close_textarea(struct html_feed_environ *h_env); +static void addnewline(Buffer * buf, char *line, Lineprop * prop, +#ifdef ANSI_COLOR + Linecolor * color, +#endif + int pos, int nlines); + +static Lineprop propBuffer[LINELEN]; +#ifdef ANSI_COLOR +static Linecolor colorBuffer[LINELEN]; +#endif + +static JMP_BUF AbortLoading; + +static struct table *tables[MAX_TABLE]; +static struct table_mode table_mode[MAX_TABLE]; + +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[MAX_SELECT]; +static int n_select; +static int cur_option_maxwidth; +#endif /* MENU_SELECT */ + +static Str cur_textarea; +Str textarea_str[MAX_TEXTAREA]; +static int cur_textarea_size; +static int cur_textarea_rows; +static int n_textarea; + +static int http_response_code; + +#ifdef JP_CHARSET +static char content_charset = '\0'; +static char guess_charset(char *p); +#ifdef NEW_FORM +static char check_charset(char *p); +static char check_accept_charset(char *p); +#endif +char DocumentCode = '\0'; +#endif + +static Str save_line = NULL; +static int save_prevchar = ' '; + +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 */ + +#ifdef NEW_FORM +#define INITIAL_FORM_SIZE 10 +static FormList **forms; +static int *form_stack; +static int form_max = 0; +static int forms_size = 0; +#define cur_form_id ((form_sp >= 0)? form_stack[form_sp] : -1) +#else /* not NEW_FORM */ +static FormList *form_stack[FORMSTACK_SIZE]; +#endif /* not NEW_FORM */ +static int form_sp = 0; + +static int current_content_length; + +static int cur_hseq; + +#define MAX_UL_LEVEL 9 +#ifdef KANJI_SYMBOLS +char *ullevel[MAX_UL_LEVEL] = +{ + "¡¦", "¢¢", "¡ù", "¡û", "¢£", "¡ú", "¡ý", "¡ü", "¢¤" +}; +#define HR_RULE "¨¬" +#define HR_RULE_WIDTH 2 +#else /* not KANJI_SYMBOLS */ +char *ullevel[MAX_UL_LEVEL] = +{ + NBSP "*", NBSP "+", NBSP "o", NBSP "#", NBSP "@", NBSP "-", + NBSP "=", "**", "--" +}; +#define HR_RULE "\212" +#define HR_RULE_WIDTH 1 +#endif /* not KANJI_SYMBOLS */ + +#ifdef USE_COOKIE +/* This array should be somewhere else */ +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 + +#define SAVE_BUF_SIZE 1536 + +#ifndef STRCHR +char * +strchr(char *s, char c) +{ + while (*s) { + if (*s == c) + return s; + s++; + } + return NULL; +} +#endif /* not STRCHR */ + +static MySignalHandler +KeyAbort(SIGNAL_ARG) +{ + LONGJMP(AbortLoading, 1); + SIGNAL_RETURN; +} + +int +currentLn(Buffer * buf) +{ + if (buf->currentLine) + return buf->currentLine->real_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 = 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; + UFclose(f); + 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); +} + +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; + + if (path == NULL) + return; + + len = strlen(path); + uf->compression = CMP_NOCOMPRESS; + if (len > 2 && strcasecmp(&path[len - 2], ".Z") == 0) { + uf->compression = CMP_COMPRESS; + uf->guess_type = "application/x-compress"; + } + else if (len > 3 && strcasecmp(&path[len - 3], ".gz") == 0) { + uf->compression = CMP_GZIP; + uf->guess_type = "application/x-gzip"; + } + else if (len > 4 && strcasecmp(&path[len - 4], ".bz2") == 0) { + uf->compression = CMP_BZIP2; + uf->guess_type = "application/x-bzip"; + } +} + +static char * +compress_application_type(int compression) +{ + switch (compression) { + case CMP_COMPRESS: + return "application/x-compress"; + case CMP_GZIP: + return "application/x-gzip"; + case CMP_BZIP2: + return "application/x-bzip"; + case CMP_DEFLATE: + return "application/x-deflate"; + default: + return NULL; + } +} + +static char * +uncompressed_file_type(char *path, char **ext) +{ + int len, slen; + Str fn; + char *t0; + + if (path == NULL) + return NULL; + + len = strlen(path); + if (len > 2 && strcasecmp(&path[len - 2], ".Z") == 0) { + slen = 2; + } + else if (len > 3 && strcasecmp(&path[len - 3], ".gz") == 0) { + slen = 3; + } + else if (len > 4 && strcasecmp(&path[len - 4], ".bz2") == 0) { + slen = 4; + } + else + 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; +} + +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; + gunzip_stream(uf); + return; + } + } +} + +/* + * convert line + */ +Str +convertLine(URLFile * uf, Str line, char *code, int mode) +{ +#ifdef JP_CHARSET + char ic; + if ((ic = checkShiftCode(line, *code)) != '\0') + line = conv_str(line, (*code = ic), InnerCode); +#endif /* JP_CHARSET */ + cleanup_line(line, mode); +#ifdef USE_NNTP + if (uf->scheme == SCM_NEWS) + Strchop(line); +#endif /* USE_NNTP */ + return line; +} + +/* + * loadFile: load file to buffer + */ +Buffer * +loadFile(char *path) +{ + URLFile uf; + init_stream(&uf, SCM_LOCAL, NULL); + examineFile(path, &uf); + if (uf.stream == NULL) + return NULL; + current_content_length = 0; + return loadSomething(&uf, path, loadBuffer, NULL); +} + +#ifdef USE_COOKIE +static 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; +} +#endif /* USE_COOKIE */ + +void +readHeader(URLFile * uf, + Buffer * newBuf, + int thru, + ParsedURL * pu) +{ + char *p, *q, *emsg; + char c; + Str lineBuf2 = NULL; + Str tmp; + TextList *headerlist; +#ifdef JP_CHARSET + char code = DocumentCode, ic; +#endif + extern int w3m_dump_head; + + 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; + + while ((tmp = StrmyUFgets(uf))->length) { +#ifdef HTTP_DEBUG + { + FILE *ff; + ff = fopen("zzrequest", "a"); + Strfputs(tmp, ff); + fclose(ff); + } +#endif /* HTTP_DEBUG */ + cleanup_line(tmp, HEADER_MODE); + if ((tmp->ptr[0] == '\n' || + tmp->ptr[0] == '\r' || + tmp->ptr[0] == '\0') +#ifdef USE_NNTP + || + (uf->scheme == SCM_NEWS && + Str_news_endline(tmp) && + (iseos(uf->stream) = TRUE)) +#endif /* USE_NNTP */ + ) { + if (!lineBuf2) + /* there is no header */ + break; + /* last header */ + } + else if (!w3m_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->ptr); +#ifdef JP_CHARSET + if ((ic = checkShiftCode(lineBuf2, code)) != '\0') + lineBuf2 = conv_str(lineBuf2, (code = ic), InnerCode); +#endif /* JP_CHARSET */ + /* 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(p), propBuffer, +#ifdef ANSI_COLOR + NULL, NULL, +#endif + min(LINELEN, q - p)); + Strcat(tmp, lineBuf2); + if (thru) + addnewline(newBuf, lineBuf2->ptr, propBuffer, +#ifdef ANSI_COLOR + NULL, +#endif + lineBuf2->length, -1); + for (; *q && (*q == '\r' || *q == '\n'); q++); + } + 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 + uf->encoding = ENC_7BIT; + } + else if (!strncasecmp(lineBuf2->ptr, "content-encoding:", 17)) { + p = lineBuf2->ptr + 17; + while (IS_SPACE(*p)) + p++; + if ((!strncasecmp(p, "x-gzip", 6) || !strncasecmp(p, "gzip", 4)) || + (!strncasecmp(p, "x-compress", 10) || !strncasecmp(p, "compress", 8))) { + uf->compression = CMP_GZIP; + } + else if (!strncasecmp(p, "x-bzip", 6) || + !strncasecmp(p, "bzip", 4) || + !strncasecmp(p, "bzip2", 5)) { + uf->compression = CMP_BZIP2; + } + else if (!strncasecmp(p, "x-deflate", 9) || + !strncasecmp(p, "deflate", 7)) { + uf->compression = CMP_DEFLATE; + } + } +#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, tmp; + 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, &tmp)) { + /* version 0 */ + expires = mymktime(tmp->ptr); + } + else if (matchattr(p, "max-age", 7, &tmp)) { + /* XXX Is there any problem with max-age=0? (RFC 2109 ss. 4.2.1, 4.2.2 */ + expires = time(NULL) + atol(tmp->ptr); + } + else if (matchattr(p, "domain", 6, &tmp)) { + domain = tmp; + } + else if (matchattr(p, "path", 4, &tmp)) { + path = tmp; + } + else if (matchattr(p, "secure", 6, NULL)) { + flag |= COO_SECURE; + } + else if (matchattr(p, "comment", 7, &tmp)) { + comment = tmp; + } + else if (matchattr(p, "version", 7, &tmp)) { + version = atoi(tmp->ptr); + } + else if (matchattr(p, "port", 4, &tmp)) { + /* version 1, Set-Cookie2 */ + port = tmp; + } + else if (matchattr(p, "commentURL", 10, &tmp)) { + /* version 1, Set-Cookie2 */ + commentURL = tmp; + } + 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 == TRUE) ? "y" : NULL; + if (fmInitialized && (err & COO_OVERRIDE_OK) && + accept_bad_cookie == PERHAPS) { + Str msg = Sprintf("Accept bad cookie from %s for %s? (y or n) ", + pu->host, domain->ptr); + if (msg->length > COLS - 4) + Strshrink(msg, msg->length - (COLS - 4)); + term_raw(); + ans = inputStr(msg->ptr, FALSE); + } + 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, 10, 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; + extern int w3mNFuncList; + + p = lineBuf2->ptr + 12; + SKIP_BLANKS(p); + while (*p && !IS_SPACE(*p)) + Strcat_char(funcname, *(p++)); + SKIP_BLANKS(p); + f = getFuncList(funcname->ptr, w3mFuncList, w3mNFuncList); + 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, +#ifdef ANSI_COLOR + NULL, +#endif + 0, -1); +} + +char * +checkHeader(Buffer * buf, char *field) +{ + int len = strlen(field); + TextListItem *i; + char *p; + + if (buf == NULL || field == NULL) + return NULL; + for (i = buf->document_header->first; i != NULL; i = i->next) { + if (!strncasecmp(i->ptr, field, len)) { + p = i->ptr + len; + SKIP_BLANKS(p); + return 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 JP_CHARSET + content_charset = '\0'; + if ((p = strcasestr(p, "charset")) != NULL) { + p += 7; + SKIP_BLANKS(p); + if (*p == '=') { + p++; + SKIP_BLANKS(p); + content_charset = guess_charset(p); + } + } +#endif + return r->ptr; +} + +static Str +extractRealm(char *q) +{ + Str p = Strnew(); + char c; + + SKIP_BLANKS(q); + if (strncasecmp(q, "Basic ", 6) != 0) { + /* complicated authentication... not implemented */ + return NULL; + } + q += 6; + SKIP_BLANKS(q); + if (strncasecmp(q, "realm=", 6) != 0) { + /* no realm attribute... get confused */ + return NULL; + } + q += 6; + SKIP_BLANKS(q); + c = '\0'; + if (*q == '"') + c = *q++; + while (*q != '\0' && *q != c) + Strcat_char(p, *q++); + return p; +} + +static Str +getAuthCookie(char *realm, char *auth_header, TextList * extra_header, ParsedURL * pu) +{ + Str ss; + Str uname, pwd; + Str tmp; + TextListItem *i, **i0; + int a_found; + int auth_header_len = strlen(auth_header); + + a_found = FALSE; + for (i0 = &(extra_header->first), i = *i0; i != NULL; i0 = &(i->next), i = *i0) { + if (!strncasecmp(i->ptr, auth_header, auth_header_len)) { + a_found = TRUE; + break; + } + } + 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); + ss = NULL; + *i0 = i->next; /* delete Authenticate: header from * + * extra_header */ + } + else + ss = find_auth_cookie(pu->host, realm); + if (ss == NULL) { + /* input username and password */ + sleep(2); + if (fmInitialized) { + char *pp; + term_raw(); + if ((pp = inputStr(Sprintf("Username for %s: ", realm)->ptr, NULL)) == NULL) + return NULL; + uname = Strnew_charp(pp); + if ((pp = inputLine(Sprintf("Password for %s: ", realm)->ptr, NULL, IN_PASSWORD)) == NULL) + return NULL; + pwd = Strnew_charp(pp); + term_cbreak(); + } + else { + printf("Username: "); + fflush(stdout); + uname = Strfgets(stdin); + Strchop(uname); + pwd = Strnew_charp((char *) getpass("Password: ")); + } + Strcat_char(uname, ':'); + Strcat(uname, pwd); + ss = encodeB(uname->ptr); + } + tmp = Strnew_charp(auth_header); + Strcat_charp(tmp, " Basic "); + Strcat(tmp, ss); + Strcat_charp(tmp, "\r\n"); + pushText(extra_header, tmp->ptr); + return ss; +} + +/* + * loadGeneralFile: load file to buffer + */ +Buffer * +loadGeneralFile(char *path, ParsedURL * current, char *referer, int flag, FormList * request) +{ + URLFile f, *of = NULL; + ParsedURL pu; + Buffer *b = NULL, *(*proc) (); + char *tpath; + char *t, *p, *real_type = NULL; + Buffer *t_buf = NULL; + int searchHeader = SearchHeader; + int searchHeader_through = TRUE; + MySignalHandler(*prevtrap) (); + TextList *extra_header = newTextList(); + Str ss; + Str realm; + int add_auth_cookie_flag; + unsigned char status = HTST_NORMAL; + URLOption url_option; + Str tmp; + extern int w3m_dump, w3m_dump_source; + + tpath = path; + prevtrap = NULL; + add_auth_cookie_flag = 0; + + if (proxy_auth_cookie != NULL) { + pushText(extra_header, Sprintf("Proxy-Authorization: Basic %s\r\n", + proxy_auth_cookie->ptr)->ptr); + } + load_doc: + url_option.referer = referer; + url_option.flag = flag; + f = openURL(tpath, &pu, current, &url_option, request, extra_header, of, &status); + of = NULL; +#ifdef JP_CHARSET + content_charset = '\0'; +#endif + if (f.stream == NULL) { + /* openURL failure: it means either (1) the requested URL is a directory name + * on an FTP server, or (2) is a local directory name. + */ + extern Str FTPDIRtmp; + if (fmInitialized && prevtrap) { + term_raw(); + signal(SIGINT, prevtrap); + } + switch (f.scheme) { + case SCM_FTPDIR: + if (FTPDIRtmp->length > 0) { + b = loadHTMLString(FTPDIRtmp); + if (b) { + if (b->currentURL.host == NULL && b->currentURL.file == NULL) + copyParsedURL(&b->currentURL, &pu); + b->real_scheme = pu.scheme; + } + return b; + } + break; + case SCM_LOCAL: + { + struct stat st; + if (stat(pu.file, &st) < 0) + return NULL; + if (S_ISDIR(st.st_mode)) { + if (UseExternalDirBuffer) { + Str tmp = Strnew_charp(DirBufferCommand); + Strcat_m_charp(tmp, "?", + pu.file, + "#current", + NULL); + b = loadGeneralFile(tmp->ptr, NULL, NO_REFERER, 0, NULL); + if (b != NULL && b != NO_BUFFER) { + copyParsedURL(&b->currentURL, &pu); + b->filename = b->currentURL.file; + } + return b; + } + else { + b = dirBuffer(pu.file); + if (b == NULL) + return NULL; + t = "text/html"; + b->real_scheme = pu.scheme; + goto loaded; + } + } + } + } + return NULL; + } + + /* openURL() succeeded */ + if (SETJMP(AbortLoading) != 0) { + /* transfer interrupted */ + if (fmInitialized) { + term_raw(); + signal(SIGINT, prevtrap); + } + if (b) + discardBuffer(b); + UFclose(&f); + return NULL; + } + + b = NULL; + if (f.is_cgi) { + /* local CGI */ + searchHeader = TRUE; + searchHeader_through = FALSE; + } + if (fmInitialized) { + prevtrap = signal(SIGINT, KeyAbort); + term_cbreak(); + } + 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) { + message(Sprintf("%s contacted. Waiting for reply...", pu.host)->ptr, 0, 0); + refresh(); + } + if (t_buf == NULL) + t_buf = newBuffer(INIT_BUFFER_WIDTH); +#ifdef USE_SSL + if (IStype(f.stream) == IST_SSL) { + Str s = ssl_get_certificate(f.stream); + if (s != NULL) + t_buf->ssl_certificate = s->ptr; + } +#endif + readHeader(&f, t_buf, FALSE, &pu); + t = checkContentType(t_buf); + if (t == NULL) + t = "text/plain"; + if (http_response_code >= 301 && http_response_code <= 303 && (p = checkHeader(t_buf, "Location:")) != NULL) { + /* document moved */ + tmp = Strnew_charp(p); + Strchop(tmp); + tpath = tmp->ptr; + request = NULL; + UFclose(&f); + add_auth_cookie_flag = 0; + current = New(ParsedURL); + copyParsedURL(current, &pu); + t_buf->bufferprop |= BP_REDIRECTED; + status = HTST_NORMAL; + goto load_doc; + } + if ((p = checkHeader(t_buf, "WWW-Authenticate:")) != NULL && + http_response_code == 401) { + /* Authentication needed */ + realm = extractRealm(p); + if (realm != NULL) { + ss = getAuthCookie(realm->ptr, "Authorization:", extra_header, &pu); + if (ss == NULL) { + /* abort */ + UFclose(&f); + signal(SIGINT, prevtrap); + return NULL; + } + 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 */ + realm = extractRealm(p); + if (realm != NULL) { + ss = getAuthCookie(realm->ptr, + "Proxy-Authorization:", + extra_header, + &HTTP_proxy_parsed); + proxy_auth_cookie = ss; + if (ss == NULL) { + /* abort */ + UFclose(&f); + signal(SIGINT, prevtrap); + return NULL; + } + UFclose(&f); + status = HTST_NORMAL; + goto load_doc; + } + } + if (add_auth_cookie_flag) + /* If authorization is required and passed */ + add_auth_cookie(pu.host, realm->ptr, ss); + if (status == HTST_CONNECT) { + of = &f; + goto load_doc; + } + } +#ifdef USE_NNTP + else if (pu.scheme == SCM_NEWS) { + 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': + t = "gopher:directory"; + break; + case 'm': + t = "gopher:directory"; + break; + 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 (t1 && strncasecmp(t1, "application/", 12) == 0) { + f.compression = CMP_NOCOMPRESS; + t = real_type; + } + else 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 (!strncasecmp(t, "application/", 12)) { + char *tmpf = tmpfname(TMPF_DFL, NULL)->ptr; + current_content_length = 0; + if (save2tmp(f, tmpf) < 0) + UFclose(&f); + else { + if (fmInitialized) { + term_raw(); + signal(SIGINT, prevtrap); + } + doFileMove(tmpf, guess_save_name(pu.file)); + } + return NO_BUFFER; + } + } + else if (searchHeader) { + t_buf = newBuffer(INIT_BUFFER_WIDTH); + readHeader(&f, t_buf, searchHeader_through, &pu); + t = checkContentType(t_buf); + if (t == NULL) + t = "text/plain"; + if (f.is_cgi && (p = checkHeader(t_buf, "Location:")) != NULL) { + /* document moved */ + tmp = Strnew_charp(p); + Strchop(tmp); + tpath = tmp->ptr; + request = NULL; + UFclose(&f); + add_auth_cookie_flag = 0; + current = New(ParsedURL); + copyParsedURL(current, &pu); + t_buf->bufferprop |= BP_REDIRECTED; + status = HTST_NORMAL; + goto load_doc; + } + searchHeader = SearchHeader = FALSE; + } + 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; + } + if (real_type == NULL) + real_type = t; + proc = loadBuffer; + + if (do_download) { + /* download only */ + if (fmInitialized) { + term_raw(); + signal(SIGINT, prevtrap); + } + doFileSave(f, guess_save_name(pu.file)); + UFclose(&f); + return NO_BUFFER; + } + + if (f.compression != CMP_NOCOMPRESS) { + if (!w3m_dump_source && + (w3m_dump || is_text_type(t) || searchExtViewer(t))) { + gunzip_stream(&f); + uncompressed_file_type(pu.file, &f.ext); + } + else { + t = compress_application_type(f.compression); + f.compression = CMP_NOCOMPRESS; + } + } + + if (!strcasecmp(t, "text/html")) + proc = loadHTMLBuffer; + else if (is_plain_text_type(t)) + proc = loadBuffer; +#ifdef USE_GOPHER + else if (!strcasecmp(t, "gopher:directory")) { + proc = loadGopherDir; + } +#endif /* USE_GOPHER */ + else if (w3m_backend) ; + else if (!w3m_dump || is_dump_text_type(t)) { + if (!do_download && doExternal(f, 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); + if (fmInitialized) { + term_raw(); + signal(SIGINT, prevtrap); + } + return b; + } + else { + if (fmInitialized) { + term_raw(); + signal(SIGINT, prevtrap); + } + if (pu.scheme == SCM_LOCAL) { + UFclose(&f); + doFileCopy(pu.file, guess_save_name(pu.file)); + } + else { + doFileSave(f, guess_save_name(pu.file)); + UFclose(&f); + } + return NO_BUFFER; + } + } + + current_content_length = 0; + if ((p = checkHeader(t_buf, "Content-Length:")) != NULL) + current_content_length = atoi(p); + + if (flag & RG_FRAME) { + t_buf = newBuffer(INIT_BUFFER_WIDTH); + t_buf->bufferprop |= BP_FRAME; + } +#ifdef USE_SSL + if (IStype(f.stream) == IST_SSL) { + Str s = ssl_get_certificate(f.stream); + if (s != NULL) + t_buf->ssl_certificate = s->ptr; + } +#endif + b = loadSomething(&f, pu.file, proc, t_buf); + UFclose(&f); + if (b) { + b->real_scheme = f.scheme; + b->real_type = real_type; + loaded: + if (b->currentURL.host == NULL && b->currentURL.file == NULL) + copyParsedURL(&b->currentURL, &pu); + if (!strcmp(t, "text/html")) + b->type = "text/html"; + else if (w3m_backend) { + Str s = Strnew_charp(t); + b->type = s->ptr; + } + else + b->type = "text/plain"; + if (pu.label) { + if (proc == loadHTMLBuffer) { + Anchor *a; +#ifdef JP_CHARSET + a = searchURLLabel(b, conv(pu.label, b->document_code, InnerCode)->ptr); +#else /* not JP_CHARSET */ + a = searchURLLabel(b, pu.label); +#endif /* not JP_CHARSET */ + if (a != NULL) { + gotoLine(b, a->start.line); + b->pos = a->start.pos; + arrangeCursor(b); + } + } + else { /* plain text */ + int l = atoi(pu.label); + gotoLine(b,l); + b->pos = 0; + arrangeCursor(b); + } + } + } + if (fmInitialized) { + term_raw(); + signal(SIGINT, prevtrap); + } + 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(int ch) +{ + switch (ch) { + case ',': + case '.': + case ':': + case ';': + case '?': + case '!': + case ')': + case ']': + case '}': + case '>': + return 1; + default: + return 0; + } +} + +static int +is_beginning_char(int ch) +{ + switch (ch) { + case '(': + case '[': + case '{': + case '`': + case '<': + return 1; + default: + return 0; + } +} + +static int +is_word_char(int ch) +{ +#ifdef JP_CHARSET + if (is_wckanji(ch) || IS_CNTRL(ch)) + return 0; +#else + if (IS_CNTRL(ch)) + return 0; +#endif + + if (IS_ALNUM(ch)) + return 1; + + switch (ch) { + case ',': + case '.': + case '\"': /* " */ + case '\'': + case '$': + case '%': + case '+': + case '-': + case '@': + case '~': + case '_': + return 1; + } + if (ch == TIMES_CODE || ch == DIVIDE_CODE || ch == ANSP_CODE) + return 0; + if (ch >= AGRAVE_CODE || ch == NBSP_CODE) + return 1; + return 0; +} + +int +is_boundary(int ch1, int 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; + + 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 */ + + if (!obuf->bp.init_flag) + return; + + obuf->bp.anchor = obuf->anchor; + obuf->bp.anchor_target = obuf->anchor_target; + obuf->bp.anchor_hseq = obuf->anchor_hseq; + 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; + obuf->anchor = obuf->bp.anchor; + obuf->anchor_target = obuf->bp.anchor_target; + obuf->anchor_hseq = obuf->bp.anchor_hseq; + 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; + 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, 0); + 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) +{ + int delta = get_mclen(mode); + append_tags(obuf); + Strcat_charp_n(obuf->line, str, len); + obuf->pos += width; + if (width > 0 && len >= delta) { + obuf->prevchar = mctowc(&str[len - delta], mode); + 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, int ch) +{ + int tlen, len = obuf->line->length; + + append_tags(obuf); + if (pre_mode) + return; + tlen = obuf->line->length - len; + if (tlen > 0 || is_boundary(obuf->prevchar, ch)) + set_breakpoint(obuf, tlen); +} + +static void +push_char(struct readbuffer *obuf, int pre_mode, char ch) +{ + check_breakpoint(obuf, pre_mode, (unsigned char)ch); + Strcat_char(obuf->line, ch); + obuf->pos++; + obuf->prevchar = (unsigned char) ch; + 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; + obuf->prevchar = ' '; + obuf->flag |= RB_NFLUSHED; +} + +static void +proc_mchar(struct readbuffer *obuf, int pre_mode, + int width, char **str, Lineprop mode) +{ + int ch = mctowc(*str, mode); + + check_breakpoint(obuf, pre_mode, ch); + obuf->pos += width; +#ifdef JP_CHARSET + if (IS_KANJI1(**str) && mode == PC_ASCII) + Strcat_char(obuf->line, ' '); + else if (mode == PC_KANJI) + Strcat_charp_n(obuf->line, *str, 2); + else +#endif + Strcat_char(obuf->line, **str); + if (width > 0) { + obuf->prevchar = ch; + if (ch != ' ') + obuf->prev_ctype = mode; + } + (*str) += get_mclen(mode); + obuf->flag |= RB_NFLUSHED; +} + +void +push_render_image(Str str, int width, struct html_feed_environ *h_env) +{ + struct readbuffer *obuf = h_env->obuf; + int indent = h_env->envs[h_env->envc].indent; + + push_str(obuf, width, str, PC_ASCII); + 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 status, 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, &status); + 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; + + if (w3m_debug) { + FILE *f = fopen("zzzproc1", "a"); + fprintf(f, "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(f, "buf=\"%s\"\n", p->ptr->line->ptr); + } + } + fclose(f); + } + + if (!(obuf->flag & (RB_SPECIAL & ~RB_NOBR)) && Strlastchar(line) == ' ') { + Strshrink(line, 1); + obuf->pos--; + } + + append_tags(obuf); + + if (obuf->anchor) + 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 && !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 (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); + } +#ifdef FORMAT_NICE + else if (obuf->flag & RB_FILL) { + char *p; + int rest, rrest; + int nspace, d, i; + + rest = width - line->length; + 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); + if (w3m_backend) { + Strcat(backend_halfdump_str, lbuf->line); + Strcat_char(backend_halfdump_str, '\n'); + } + } + else { + Strfputs(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); \ + if (w3m_backend) \ + Strcat(backend_halfdump_str, (str)); \ + } else \ + 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; + } + } + obuf->line = Strnew_size(256); + obuf->pos = 0; + 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) { + 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, htmlquote_str(obuf->anchor->ptr)); + if (obuf->anchor_target) { + Strcat_charp(tmp, "\" TARGET=\""); + Strcat_charp(tmp, htmlquote_str(obuf->anchor_target->ptr)); + } + 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, htmlquote_str(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); +} + +static void +discardline(struct readbuffer *obuf, int indent) +{ + append_tags(obuf); + Strclear(obuf->line); + obuf->pos = 0; + obuf->prevchar = ' '; + obuf->bp.init_flag = 1; + set_breakpoint(obuf, 0); + obuf->prev_ctype = PC_ASCII; + fillline(obuf, indent); +} + +void +do_blankline(struct html_feed_environ *h_env, struct readbuffer *obuf, int indent, int indent_incr, int width) +{ + if (h_env->buf && h_env->blank_lines == 0) + flushline(h_env, obuf, indent, 1, width); + else if (h_env->f) + 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) { + 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); + 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); + } + obuf->anchor = NULL; + obuf->anchor_target = NULL; + return; + } + is_erased = 0; + } + if (is_erased) { + Strcat_char(obuf->line, ' '); + obuf->pos++; + } + + push_tag(obuf, "</a>", HTML_N_A); + obuf->anchor = NULL; + } + obuf->anchor_target = NULL; +} + +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); +} + + +Str +process_img(struct parsed_tag * tag) +{ + char *p, *q, *r, *r2, *s; + int w, i; + Str tmp = Strnew(); + + if (!parsedtag_get_value(tag, ATTR_SRC, &p)) + return tmp; + q = NULL; + parsedtag_get_value(tag, ATTR_ALT, &q); + w = -1; + parsedtag_get_value(tag, ATTR_WIDTH, &w); + i = -1; + parsedtag_get_value(tag, ATTR_HEIGHT, &i); + r = NULL; + parsedtag_get_value(tag, ATTR_USEMAP, &r); + + tmp = Strnew_size(128); + if (r) { + r2 = strchr(r, '#'); +#ifdef NEW_FORM + s = "<form_int method=internal action=map>"; + process_form(parse_tag(&s, TRUE)); + Strcat(tmp, Sprintf("<pre_int><input_alt fid=\"%d\" " + "type=hidden name=link value=\"", + cur_form_id)); + Strcat_charp(tmp, htmlquote_str((r2) ? r2 + 1 : r)); + Strcat(tmp, Sprintf("\"><input_alt hseq=\"%d\" fid=\"%d\" " + "type=submit no_effect=true>", + cur_hseq++, cur_form_id)); +#else /* not NEW_FORM */ + Strcat_charp(tmp, "<form_int method=internal action=map>" + "<pre_int><input_alt type=hidden name=link value=\""); + Strcat_charp(tmp, htmlquote_str((r2) ? r2 + 1 : r)); + Strcat(tmp, Sprintf("\"><input_alt hseq=\"%d\" type=submit " + "no_effect=true>", cur_hseq++)); +#endif /* not NEW_FORM */ + } + if (q != NULL && *q == '\0' && ignore_null_img_alt) + q = NULL; + if (q != NULL || r != NULL) + Strcat_charp(tmp, "<img_alt src=\""); + else + Strcat_charp(tmp, "<nobr><img_alt src=\""); + Strcat_charp(tmp, htmlquote_str(p)); + Strcat_charp(tmp, "\">"); + if (q != NULL) { + Strcat_charp(tmp, htmlquote_str(q)); + Strcat_charp(tmp, "</img_alt> "); + goto img_end2; + } + if (w > 0 && i > 0) { + /* guess what the image is! */ + if (w < 32 && i < 48) { + /* must be an icon or space */ + if (strcasestr(p, "space") || strcasestr(p, "blank")) + Strcat_charp(tmp, "_</img_alt>"); + else { + if (w * i < 8 * 16) + Strcat_charp(tmp, "*</img_alt>"); + else { +#ifdef KANJI_SYMBOLS + Strcat_charp(tmp, "¡ü</img_alt>"); +#else /* not KANJI_SYMBOLS */ + Strcat_charp(tmp, "#</img_alt>"); +#endif /* not KANJI_SYMBOLS */ + } + } + goto img_end1; + } + if (w > 200 && i < 13) { + /* must be a horizontal line */ +#ifndef KANJI_SYMBOLS + Strcat_charp(tmp, "<_RULE>"); +#endif /* not KANJI_SYMBOLS */ + w /= pixel_per_char; + for (i = 0; i < w - (HR_RULE_WIDTH - 1); i += HR_RULE_WIDTH) + Strcat_charp(tmp, HR_RULE); +#ifndef KANJI_SYMBOLS + Strcat_charp(tmp, "</_RULE>"); +#endif /* not KANJI_SYMBOLS */ + Strcat_charp(tmp, "</img_alt>"); + goto img_end1; + } + } + for (q = p; *q; q++); + while (q > p && *q != '/') + q--; + if (*q == '/') + q++; + Strcat_char(tmp, '['); + p = q; + for (; *q; q++) { + if (!IS_ALNUM(*q) && *q != '_' && *q != '-') { + break; + } + else if (w > 0 && !IS_ALNUM(*q) && q - p + 2 > (int)(w / pixel_per_char)) { + Strcat_charp(tmp, ".."); + break; + } + Strcat_char(tmp, *q); + } + Strcat_charp(tmp, "]</img_alt>"); + img_end1: + if (r == NULL) + Strcat_charp(tmp, "</nobr>"); + img_end2: + if (r) { +#ifdef NEW_FORM + Strcat_charp(tmp, "</input_alt></pre_int>"); + process_n_form(); +#else /* not NEW_FORM */ + Strcat_charp(tmp, "</input_alt></pre_int></form_int>"); +#endif /* not NEW_FORM */ + } + 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; + char *q , *p, *r, *p2; + Str tmp; + char *qq = ""; + int qlen = 0; + + 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); + + 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=CHECHBOX> 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 = htmlquote_str(q); + qlen = strlen(q); + } + + tmp = Strnew_charp("<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, '('); + } +#ifdef NEW_FORM + 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, htmlquote_str(r), w, i, qq)); +#else /* not NEW_FORM */ + Strcat(tmp, Sprintf("<input_alt hseq=\"%d\" type=%s " + "name=\"%s\" width=%d maxlength=%d value=\"%s\"", + cur_hseq++, p, htmlquote_str(r), w, i, qq)); +#endif /* not NEW_FORM */ + if (x) + Strcat_charp(tmp, " checked"); + if (y) + Strcat_charp(tmp, " accept"); + 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: + 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_IMAGE: + case FORM_INPUT_SUBMIT: + case FORM_INPUT_BUTTON: + if (p2) { + Strcat_charp(tmp, htmlquote_str(p2)); + i = strlen(p2); + } + else { + Strcat_charp(tmp, qq); + i = qlen; + } + break; + case FORM_INPUT_RESET: + Strcat_charp(tmp, qq); + i = qlen; + 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; +} + +void +process_select(struct parsed_tag * tag) +{ + char *p; + + 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 && n_select < MAX_SELECT) { +#ifdef NEW_FORM + select_str = Sprintf("<pre_int>[<input_alt hseq=\"%d\" " + "fid=\"%d\" type=select name=\"%s\" selectnumber=%d", + cur_hseq++, cur_form_id, htmlquote_str(p), n_select); +#else /* not NEW_FORM */ + select_str = Sprintf("<pre_int><input_alt hseq=\"%d\" " + "type=select name=\"%s\" selectnumber=%d", + cur_hseq++, htmlquote_str(p), n_select); +#endif /* not NEW_FORM */ + Strcat_charp(select_str, ">"); + 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; +} + +Str +process_n_select(void) +{ + if (cur_select == NULL) + return NULL; + process_option(); +#ifdef MENU_SELECT + if (!select_is_multiple && n_select < MAX_SELECT) { + if (select_option[n_select].first) + Strcat(select_str, textfieldrep(chooseSelectOption( + select_option[n_select].first, CHOOSE_OPTION), + cur_option_maxwidth)); + Strcat_charp(select_str, "</input_alt>]</pre_int>"); + n_select++; + if (n_select == MAX_SELECT) { + disp_err_message("Too many select in one page", FALSE); + } + } 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 = ']'; + + 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 && n_select < MAX_SELECT) { + if (cur_option_label->length > cur_option_maxwidth) + cur_option_maxwidth = cur_option_label->length; + addSelectOption(&select_option[n_select], + cur_option_value, + cur_option_label, + cur_option_selected); + return; + } +#endif /* MENU_SELECT */ +#ifdef NEW_FORM + 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, +#else /* not NEW_FORM */ + Strcat(select_str, Sprintf("<br><pre_int><input_alt hseq=\"%d\" " + "type=%s name=\"%s\" value=\"%s\"", + cur_hseq++, +#endif /* not NEW_FORM */ + select_is_multiple ? "checkbox" : "radio", + htmlquote_str(cur_select->ptr), + htmlquote_str(cur_option_value->ptr))); + if (cur_option_selected) + Strcat_charp(select_str, " checked>*</input_alt>"); + else + Strcat_charp(select_str, "> </input_alt>"); +#ifdef NEW_FORM + Strcat_char(select_str, end_char); +#endif /* not NEW_FORM */ + Strcat_charp(select_str, htmlquote_str(cur_option_label->ptr)); + Strcat_charp(select_str, "</pre_int>"); + n_selectitem++; +} + +Str +process_textarea(struct parsed_tag * tag, int width) +{ + char *p, *q, *r; + + p = "40"; + parsedtag_get_value(tag, ATTR_COLS, &p); + q = ""; + parsedtag_get_value(tag, ATTR_NAME, &q); + r = "10"; + parsedtag_get_value(tag, ATTR_ROWS, &r); + cur_textarea = Strnew_charp(q); + 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 = 40; + + cur_textarea_rows = atoi(r); + if (n_textarea < MAX_TEXTAREA) + textarea_str[n_textarea] = Strnew(); + + return NULL; +} + +Str +process_n_textarea(void) +{ + Str tmp; + + if (cur_textarea == NULL || n_textarea >= MAX_TEXTAREA) + return NULL; + +#ifdef NEW_FORM + tmp = Sprintf("<pre_int>[<input_alt hseq=\"%d\" fid=\"%d\" type=textarea " + "name=\"%s\" size=%d rows=%d textareanumber=%d><u>", + cur_hseq++, cur_form_id, htmlquote_str(cur_textarea->ptr), + cur_textarea_size, cur_textarea_rows, n_textarea); +#else /* not NEW_FORM */ + tmp = Sprintf("<pre_int>[<input_alt hseq=\"%d\" type=textarea " + "name=\"%s\" size=%d rows=%d textareanumber=%d><u>", + cur_hseq++, htmlquote_str(cur_textarea->ptr), + cur_textarea_size, cur_textarea_rows, n_textarea); +#endif /* not NEW_FORM */ + Strcat(tmp, textfieldrep(textarea_str[n_textarea], cur_textarea_size)); + Strcat_charp(tmp, "</u></input_alt>]</pre_int>"); + n_textarea++; + if (n_textarea == MAX_TEXTAREA) { + disp_err_message("Too many textarea in one page", FALSE); + } + else + textarea_str[n_textarea] = Strnew(); + cur_textarea = NULL; + + return tmp; +} + +void +feed_textarea(char *str) +{ + if (n_textarea < MAX_TEXTAREA) { + 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 + 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 i,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 align=center>"); + break; + case ALIGN_RIGHT: + Strcat_charp(tmp,"<div align=right>"); + break; + case ALIGN_LEFT: + Strcat_charp(tmp,"<div align=left>"); + break; + } +#ifndef KANJI_SYMBOLS + Strcat_charp(tmp, "<_RULE>"); +#endif /* not KANJI_SYMBOLS */ + w -= HR_RULE_WIDTH - 1; + if (w <= 0) + w = 1; + for (i = 0; i < w; i += HR_RULE_WIDTH) { + Strcat_charp(tmp, HR_RULE); + } +#ifndef KANJI_SYMBOLS + Strcat_charp(tmp, "</_RULE>"); +#endif /* not KANJI_SYMBOLS */ + Strcat_charp(tmp,"</div></nobr>"); + return tmp; +} + +#ifdef NEW_FORM +#ifdef JP_CHARSET +char +check_charset(char *s) +{ + switch (*s) { + case CODE_EUC: + case CODE_SJIS: + case CODE_JIS_n: + case CODE_JIS_m: + case CODE_JIS_N: + case CODE_JIS_j: + case CODE_JIS_J: + case CODE_INNER_EUC: + return *s; + } + return 0; +} + +char +check_accept_charset(char *s) +{ + char *e; + char c; + + while (*s) { + while (*s && (IS_SPACE(*s) || *s == ',')) + s++; + if (!*s) + break; + e = s; + while (*e && !(IS_SPACE(*e) || *e == ',')) + e++; + c = guess_charset(Strnew_charp_n(s, e - s)->ptr); + if (c) + return c; + s = e; + } + return 0; +} +#endif + +Str +process_form(struct parsed_tag *tag) +{ + char *p, *q, *r, *s, *tg; + char cs = 0; + + p = "get"; + parsedtag_get_value(tag, ATTR_METHOD, &p); + q = "!CURRENT_URL!"; + parsedtag_get_value(tag, ATTR_ACTION, &q); + r = NULL; +#ifdef JP_CHARSET + if (parsedtag_get_value(tag, ATTR_ACCEPT_CHARSET, &r)) + cs = check_accept_charset(r); + if (! cs && parsedtag_get_value(tag, ATTR_CHARSET, &r)) + cs = check_charset(r); +#endif + s = NULL; + parsedtag_get_value(tag, ATTR_ENCTYPE, &s); + tg = NULL; + parsedtag_get_value(tag, ATTR_TARGET, &tg); + form_max++; + form_sp++; + if (forms_size == 0) { + forms_size = INITIAL_FORM_SIZE; + forms = New_N(FormList *, forms_size); + form_stack = New_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); + } + forms[form_max] = + newFormList(q, p, &cs, s, tg, (form_max > 0) ? forms[form_max - 1] : NULL); + form_stack[form_sp] = form_max; + + return NULL; +} + +Str +process_n_form(void) +{ + if (form_sp >= 0) + form_sp--; + return NULL; +} +#endif /* NEW_FORM */ + +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\">", + htmlquote_str(id), htmlquote_str(framename)); + else + idtag = Sprintf("<_id id=\"%s\">", htmlquote_str(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);\ + close_anchor(h_env, obuf);\ + obuf->flag &= ~RB_P;\ + } + +#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 +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_P: + case HTML_N_P: + CLOSE_P; + 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_EOL: + if ((obuf->flag & RB_PREMODE) && obuf->pos > envs[h_env->envc].indent) + flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); + 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_P; + 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); + if (cmd == HTML_BLQ) + 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_P; + 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_P; + 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_P; + 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); + switch (envs[h_env->envc].type) { +#ifdef KANJI_SYMBOLS + case 'd': + push_charp(obuf, 2, "¡ü", PC_ASCII); + break; + case 'c': + push_charp(obuf, 2, "¡û", PC_ASCII); + break; + case 's': + push_charp(obuf, 2, "¢¢", PC_ASCII); + break; +#endif /* KANJI_SYMBOLS */ + default: + push_charp(obuf, 2, ullevel[(h_env->envc_real - 1) % MAX_UL_LEVEL], PC_ASCII); + break; + } + push_charp(obuf, 1, NBSP, PC_ASCII); + 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 /* INDENT_INCR < 4 */ + Strcat_char(num, '.'); +#endif /* INDENT_INCR < 4 */ + push_spaces(obuf, 1, INDENT_INCR - num->length); + push_str(obuf, num->length, num, PC_ASCII); + 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_P; + 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_P; + 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: + append_tags(obuf); + save_line = obuf->line; + save_prevchar = obuf->prevchar; + set_breakpoint(obuf, 0); + obuf->line = Strnew(); + discardline(obuf, 0); + obuf->flag |= (RB_NOBR | RB_TITLE); + return 1; + case HTML_N_TITLE: + if (!(obuf->flag & RB_TITLE)) + return 1; + obuf->flag &= ~(RB_NOBR | RB_TITLE); + append_tags(obuf); + tmp = Strnew_charp(obuf->line->ptr); + Strremovetrailingspaces(tmp); + h_env->title = cleanup_str(tmp->ptr); + obuf->line = save_line; + obuf->prevchar = save_prevchar; + back_to_breakpoint(obuf); + tmp = Strnew_m_charp( + "<title_alt title=\"", + htmlquote_str(h_env->title), + "\">", + NULL); + push_tag(obuf, tmp->ptr, HTML_TITLE_ALT); + return 1; + 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_FRAME: + q = r = NULL; + parsedtag_get_value(tag, ATTR_SRC, &q); + parsedtag_get_value(tag, ATTR_NAME, &r); + if (q) { + q = htmlquote_str(q); + push_tag(obuf, Sprintf("<a hseq=\"%d\" href=\"%s\">", + cur_hseq++, q)->ptr, HTML_A); + if (r) + q = htmlquote_str(r); + push_charp(obuf, strlen(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: + tmp = process_hr(tag,h_env->limit,envs[h_env->envc].indent); + HTMLlineproc1(tmp->ptr,h_env); + obuf->prevchar = ' '; + close_anchor(h_env, obuf); + return 1; + case HTML_PRE: + if (!parsedtag_exists(tag, ATTR_FOR_TABLE)) + CLOSE_P; + if (!(obuf->flag & RB_IGNORE_P)) + flushline(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); + 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) { + 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_LISTING: + CLOSE_P; + flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); + obuf->flag |= (RB_LSTMODE | RB_IGNORE_P); + /* istr = str; */ + return 1; + case HTML_N_LISTING: + CLOSE_P; + flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); + obuf->flag &= ~RB_LSTMODE; + return 1; + case HTML_XMP: + CLOSE_P; + flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); + obuf->flag |= (RB_XMPMODE | RB_IGNORE_P); + /* istr = str; */ + return 1; + case HTML_N_XMP: + CLOSE_P; + flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); + obuf->flag &= ~RB_XMPMODE; + return 1; + case HTML_SCRIPT: + obuf->flag |= RB_IGNORE; + obuf->ignore_tag = Strnew_charp("</script>"); + return 1; + case HTML_N_SCRIPT: + /* should not be reached */ + return 1; + case HTML_STYLE: + obuf->flag |= RB_IGNORE; + obuf->ignore_tag = Strnew_charp("</style>"); + return 1; + case HTML_N_STYLE: + /* should not be reached */ + return 1; + case HTML_PLAINTEXT: + flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); + obuf->flag |= RB_PLAIN; + /* istr = str; */ + return 1; + case HTML_A: + if (obuf->anchor) + close_anchor(h_env, obuf); + + hseq = 0; + + if (parsedtag_get_value(tag, ATTR_HREF, &p)) + obuf->anchor = Strnew_charp(p); + if (parsedtag_get_value(tag, ATTR_TARGET, &p)) + obuf->anchor_target = Strnew_charp(p); + if (parsedtag_get_value(tag, ATTR_HSEQ, &hseq)) + obuf->anchor_hseq = hseq; + + if (hseq == 0 && obuf->anchor) { + 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); + 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); + 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_TABLE: + 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; +#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_P; + 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_P; + 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_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: + CLOSE_P; + flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); + RB_RESTORE_FLAG(obuf); + return 1; + case HTML_FORM: +#ifdef NEW_FORM + case HTML_FORM_INT: + process_form(tag); + return 1; +#endif /* NEW_FORM */ + case HTML_N_FORM: +#ifdef NEW_FORM + case HTML_N_FORM_INT: + process_n_form(); + return 1; +#else /* not NEW_FORM */ + flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); + return 0; +#endif /* not NEW_FORM */ + case HTML_INPUT: + tmp = process_input(tag); + if (tmp) + HTMLlineproc1(tmp->ptr, h_env); + return 1; + case HTML_SELECT: + process_select(tag); + obuf->flag |= RB_INSELECT; + return 1; + case HTML_N_SELECT: + obuf->flag &= ~RB_INSELECT; + tmp = process_n_select(); + if (tmp) + HTMLlineproc1(tmp->ptr, h_env); + return 1; + case HTML_OPTION: + /* nothing */ + return 1; + case HTML_TEXTAREA: + process_textarea(tag, h_env->limit); + obuf->flag |= RB_INTXTA; + return 1; + case HTML_N_TEXTAREA: + close_textarea(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=\"", + htmlquote_str(q), + "\">", + htmlquote_str(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 JP_CHARSET + if (p && q && !strcasecmp(p, "Content-Type") && + (q = strcasestr(q, "charset")) != NULL) { + q += 7; + SKIP_BLANKS(q); + if (*q == '=') { + q++; + SKIP_BLANKS(q); + content_charset = guess_charset(q); + } + } + else +#endif + if (p && q && !strcasecmp(p, "refresh")) { + int refresh = atoi(q); + Str s_tmp = NULL; + + 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++; + } + if (s_tmp) { + q = htmlquote_str(s_tmp->ptr); + tmp = Sprintf("Refresh (%d sec) <a hseq=\"%d\" href=\"%s\">%s</a>", + refresh, cur_hseq++, q, q); + push_str(obuf, s_tmp->length, tmp, PC_ASCII); + flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); + if (!is_redisplay && refresh == 0) { + pushEvent(FUNCNAME_goURL, s_tmp->ptr); + /* pushEvent(deletePrevBuf,NULL); */ + } + } + } + return 1; + case HTML_BASE: + case HTML_MAP: + case HTML_N_MAP: + case HTML_AREA: + return 0; + case HTML_DEL: + HTMLlineproc1("<U>[DEL:</U>", h_env); + return 1; + case HTML_N_DEL: + HTMLlineproc1("<U>:DEL]</U>", h_env); + return 1; + case HTML_INS: + HTMLlineproc1("<U>[INS:</U>", h_env); + return 1; + case HTML_N_INS: + HTMLlineproc1("<U>:INS]</U>", h_env); + return 1; + case HTML_FONT: + case HTML_N_FONT: + case HTML_NOP: + return 1; +#ifdef VIEW_UNSEENOBJECTS + case HTML_BGSOUND: + if (view_unseenobject) { + if (parsedtag_get_value(tag, ATTR_SRC, &p)) { + Str s; + q = htmlquote_str(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 = htmlquote_str(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 = htmlquote_str(p); + s = Sprintf("<A HREF=\"%s\">applet archive(%s)</A>", q, q); + HTMLlineproc1(s->ptr, h_env); + } + } + return 1; +#endif /* VIEW_UNSEENOBJECTS */ + case HTML_BODY: +#ifdef VIEW_UNSEENOBJECTS + if (view_unseenobject) { + if (parsedtag_get_value(tag, ATTR_BACKGROUND, &p)) { + Str s; + q = htmlquote_str(p); + s = Sprintf("<IMG SRC=\"%s\" ALT=\"bg image(%s)\"><BR>", + q, q); + HTMLlineproc1(s->ptr, h_env); + } + } +#endif /* VIEW_UNSEENOBJECTS */ + case HTML_N_BODY: + obuf->flag |= RB_IGNORE_P; + return 1; + default: +/* obuf->prevchar = '\0'; */ + return 0; + } + /* not reached */ + return 0; +} + +#define PPUSH(p,c) {outp[pos]=(p);outc[pos]=(c);pos++;} + +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) +{ + Anchor *a_href = NULL, *a_img = NULL, *a_form = NULL; + char outc[LINELEN]; + char *p, *q, *r, *str; +#ifndef NEW_FORM + char cs; +#endif + Lineprop outp[LINELEN], mode, effect; + int pos; + int nlines; + FILE *debug; + struct frameset *frameset_s[FRAMESTACK_SIZE]; + int frameset_sp = -1; + union frameset_element *idFrame = NULL; + char *id = NULL; + Str tmp; + int hseq; + Str line; + char *endp; + + if (w3m_debug) + debug = fopen("zzzerr", "a"); + + effect = 0; + nlines = 0; +#ifdef NEW_FORM + buf->formlist = (form_max >= 0) ? forms[form_max] : NULL; +#endif /* NEW_FORM */ + while ((line = feed()) != NULL) { + if (w3m_debug) { + Strfputs(line, debug); + fputc('\n', debug); + } + proc_again: + if (++nlines == llimit) + break; + pos = 0; + if (showLineNum) { + tmp = Sprintf("%4d:", nlines); + for (p = tmp->ptr; *p; p++) { + PPUSH(PC_ASCII, *p); + } + } +#ifdef ENABLE_REMOVE_TRAILINGSPACES + Strremovetrailingspaces(line); +#endif + str = line->ptr; + endp = str + line->length; + while (str < endp && pos < LINELEN) { + mode = get_mctype(str); +#ifndef KANJI_SYMBOLS + if (effect & PC_RULE && IS_INTSPACE(*str)) { + PPUSH(PC_ASCII | effect, *str); + str++; + } else +#endif + if (mode == PC_CTRL || IS_INTSPACE(*str)) { + PPUSH(PC_ASCII | effect, ' '); + str++; + } +#ifdef JP_CHARSET + else if (mode == PC_KANJI) { + PPUSH(PC_KANJI1 | effect, str[0]); + PPUSH(PC_KANJI2 | effect, str[1]); + str += 2; + } +#endif + else if (mode == PC_ASCII && *str != '<' && *str != '&') { + PPUSH(mode | effect, *(str++)); + } + else if (*str == '&') { + /* + * & escape processing + */ + int emode; + p = getescapecmd(&str); + while (*p) { + emode = get_mctype(p); +#ifdef JP_CHARSET + if (emode == PC_KANJI) { + PPUSH(PC_KANJI1 | effect, p[0]); + PPUSH(PC_KANJI2 | effect, p[1]); + p += 2; + } + else +#endif + { + PPUSH(emode | effect, *(p++)); + } + } + } + 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) && + (!idFrame || strcmp(idFrame->body->name, p))) { + idFrame = search_frame(renderFrameSet, p); + if (idFrame && idFrame->body->attr != F_BODY) + idFrame = NULL; + } + p = r = NULL; + q = buf->baseTarget; + hseq = 0; + id = NULL; + if (parsedtag_get_value(tag, ATTR_NAME, &id)) + registerName(buf, id, currentLn(buf), pos); + parsedtag_get_value(tag, ATTR_HREF, &p); + parsedtag_get_value(tag, ATTR_TARGET, &q); + parsedtag_get_value(tag, ATTR_REFERER, &r); + 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, + currentLn(buf), + pos); + if (p) { + effect |= PE_ANCHOR; + a_href = registerHref(buf, remove_space(p), q, + r, currentLn(buf), pos); + a_href->hseq = ((hseq > 0) ? hseq : -hseq) - 1; + } + 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_IMG_ALT: + if (parsedtag_get_value(tag, ATTR_SRC, &p)) { + a_img = registerImg(buf, p, + currentLn(buf), pos); + } + 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; +#ifdef NEW_FORM + int form_id = -1; +#endif /* NEW_FORM */ + +#ifndef NEW_FORM + if (form_sp < 0) + break; /* outside of <form>..</form> */ +#endif /* not NEW_FORM */ + hseq = 0; + parsedtag_get_value(tag, ATTR_HSEQ, &hseq); +#ifdef NEW_FORM + parsedtag_get_value(tag, ATTR_FID, &form_id); +#endif +#ifdef NEW_FORM + if (form_id < 0 || form_id > form_max || forms == NULL) + break; /* outside of <form>..</form> */ + form = forms[form_id]; +#else /* not NEW_FORM */ + if (form_sp >= FORMSTACK_SIZE) + break; + form = form_stack[form_sp]; +#endif /* not NEW_FORM */ + 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; + a_form = registerForm(buf, form, tag, currentLn(buf), pos); + if (a_form) { + a_form->hseq = hseq - 1; + 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; +#ifndef NEW_FORM + case HTML_FORM: + case HTML_FORM_INT: + form_sp++; + if (form_sp >= FORMSTACK_SIZE) + break; + p = "get"; + q = "/"; + s = NULL; + cs = 0; + parsedtag_get_value(tag, ATTR_METHOD, &p); + parsedtag_get_value(tag, ATTR_ACTION, &q); +#ifdef JP_CHARSET + if (parsedtag_get_value(tag, ATTR_CHARSET, &r)) + cs = check_charset(r); +#endif + parsedtag_get_value(tag, ATTR_ENCTYPE, &s); + buf->formlist = newFormList(q, p, &cs, s, buf->formlist); + form_stack[form_sp] = buf->formlist; + break; + case HTML_N_FORM: + case HTML_N_FORM_INT: + if (form_sp >= 0) + form_sp--; + break; +#endif /* not NEW_FORM */ + case HTML_MAP: + if (parsedtag_get_value(tag, ATTR_NAME, &p)) { + MapList *m = New(MapList); + m->name = Strnew_charp(p); + m->next = buf->maplist; + m->urls = newTextList(); + m->alts = newTextList(); + 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)) { + pushText(buf->maplist->urls, p); + if (parsedtag_get_value(tag, ATTR_ALT, &q)) + pushText(buf->maplist->alts, q); + else + pushText(buf->maplist->alts, ""); + } + 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], 0, 0); + } + 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, baseURL(buf)); + addFrameSetElement(frameset_s[frameset_sp], element); + } + break; + case HTML_BASE: + if (parsedtag_get_value(tag, ATTR_HREF, &p)) { + if (!buf->baseURL) + buf->baseURL = New(ParsedURL); + parseURL(p, buf->baseURL, NULL); + } + parsedtag_get_value(tag, ATTR_TARGET, &buf->baseTarget); + break; + case HTML_TITLE_ALT: + if (parsedtag_get_value(tag, ATTR_TITLE, &p)) + buf->buffername = cleanup_str(p); + break; +#ifndef KANJI_SYMBOLS + case HTML_RULE: + effect |= PC_RULE; + break; + case HTML_N_RULE: + effect &= ~PC_RULE; + break; +#endif /* not KANJI_SYMBOLS */ + } +#ifdef ID_EXT + id = NULL; + if (parsedtag_get_value(tag, ATTR_ID, &id)) + registerName(buf, id, currentLn(buf), pos); + if (renderFrameSet && + parsedtag_get_value(tag, ATTR_FRAMENAME, &p) && + (!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, + currentLn(buf), pos); +#endif /* ID_EXT */ + } + } + /* end of processing for one line */ + addnewline(buf, outc, outp, +#ifdef ANSI_COLOR + NULL, +#endif + pos, nlines); + if (str != endp) { + line = Strsubstr(line, str - line->ptr, endp - str); + goto proc_again; + } + } + if (w3m_debug) + fclose(debug); +} + +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 = IS_CNTRL(ech) ? PC_CTRL : PC_ASCII; + + if (!ech) { + *str_return = str; + proc_mchar(obuf, obuf->flag & RB_SPECIAL, 1, str_return, PC_ASCII); + return; + } + + check_breakpoint(obuf, obuf->flag & RB_SPECIAL, ech); + estr = conv_latin1(ech); + width = strlen(estr); + if (width == 1 && ech == (unsigned char) *estr && + ech != '&' && ech != '<' && ech != '>') + push_charp(obuf, width, estr, mode); + else + push_nchars(obuf, width, str, n_add, mode); + obuf->prevchar = ech; + obuf->prev_ctype = mode; +} + + +static int +need_flushline(struct html_feed_environ *h_env, struct readbuffer *obuf, + Lineprop mode) +{ + char ch = Strlastchar(obuf->line); + + if (obuf->flag & RB_PRE_INT) { + if (obuf->pos > h_env->limit) + return 1; + else + return 0; + } + + /* 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 *istr, struct html_feed_environ *h_env, int internal) +{ + Lineprop mode; + char *str = istr, *q; + int cmd; + struct readbuffer *obuf = h_env->obuf; + int indent, delta; + struct parsed_tag *tag; + Str tokbuf = Strnew(); + struct table *tbl = NULL; + struct table_mode *tbl_mode; + int tbl_width; + + 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_IGNORE) ? 'I' : ' '); + fprintf(f, "HTMLlineproc1(\"%s\",%d,%lx)\n", istr, h_env->limit, (unsigned long) h_env); + fclose(f); + } + + /* comment processing */ + if (obuf->status == R_ST_CMNT || obuf->status == R_ST_NCMNT3 || + obuf->status == R_ST_IRRTAG) { + while (*str != '\0' && obuf->status != R_ST_NORMAL) { + next_status(*str, &obuf->status); + str++; + } + if (obuf->status != R_ST_NORMAL) + return; + } + + 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 (*str != '\0') { + int is_tag = FALSE; + + if (obuf->flag & RB_PLAIN) + goto read_as_plain; /* don't process tag */ + + if (*str == '<' || ST_IS_TAG(obuf->status)) { + int pre_mode = (obuf->table_level >= 0) ? + tbl_mode->pre_mode & TBLM_PLAIN : + obuf->flag & RB_PLAINMODE; + /* + * Tag processing + */ + if (ST_IS_TAG(obuf->status)) { +/*** continuation of a tag ***/ + read_token(h_env->tagbuf, &str, &obuf->status, + pre_mode, 1); + } + else { + if (!REALLY_THE_BEGINNING_OF_A_TAG(str)) { + /* this is NOT a beginning of a tag */ + obuf->status = R_ST_NORMAL; + HTMLlineproc1("<", h_env); + str++; + continue; + } + read_token(h_env->tagbuf, &str, &obuf->status, + pre_mode, 0); + } + if (ST_IS_COMMENT(obuf->status)) { + if (obuf->flag & RB_IGNORE) + /* within ignored tag, such as * + * <script>..</script>, don't process comment. */ + obuf->status = R_ST_NORMAL; + return; + } + if (h_env->tagbuf->length == 0) + continue; + if (obuf->status != R_ST_NORMAL) { + if (!pre_mode) { + if (Strlastchar(h_env->tagbuf) == '\n') + Strchop(h_env->tagbuf); + if (ST_IS_REAL_TAG(obuf->status)) + Strcat_char(h_env->tagbuf, ' '); + } + continue; + } + is_tag = TRUE; + q = h_env->tagbuf->ptr; + } + + if (obuf->flag & (RB_INTXTA + | RB_INSELECT + | RB_IGNORE)) { + cmd = HTML_UNKNOWN; + if (!is_tag) { + read_token(tokbuf, &str, &obuf->status, + (obuf->flag & RB_INTXTA) ? 1 : 0, 0); + if (obuf->status != R_ST_NORMAL) + continue; + q = tokbuf->ptr; + } + else { + char *p = q; + cmd = gethtmlcmd(&p, NULL); + } + + /* textarea */ + if (obuf->flag & RB_INTXTA) { + if (cmd == HTML_N_TEXTAREA) + goto proc_normal; + feed_textarea(q); + } + else if (obuf->flag & RB_INSELECT) { + if (cmd == HTML_N_SELECT || cmd == HTML_N_FORM) + goto proc_normal; + feed_select(q); + } + /* script */ + else if (obuf->flag & RB_IGNORE) { + if (TAG_IS(q, obuf->ignore_tag->ptr, + obuf->ignore_tag->length - 1)) { + obuf->flag &= ~RB_IGNORE; + } + } + continue; + } + + 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. + */ + + if (!is_tag) { + read_token(tokbuf, &str, &obuf->status, + tbl_mode->pre_mode & TBLM_PREMODE, 0); + if (obuf->status != R_ST_NORMAL) + continue; + q = tokbuf->ptr; + } + + switch (feed_table(tbl, q, 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) { + Str tmp; + struct table *tbl0 = tables[obuf->table_level]; + tmp = Sprintf("<table_alt tid=%d>", tbl0->ntable); + pushTable(tbl0, tbl); + tbl = tbl0; + tbl_mode = &table_mode[obuf->table_level]; + tbl_width = table_width(h_env, obuf->table_level); + feed_table(tbl, tmp->ptr, tbl_mode, tbl_width, TRUE); + continue; + /* continue to the next */ + } + /* 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; + } + obuf->prevchar = ' '; + continue; + case 1: + /* <table> tag */ + goto proc_normal; + default: + continue; + } + } + + proc_normal: + if (is_tag) { +/*** Beginning of a new tag ***/ + if ((tag = parse_tag(&q, internal))) + cmd = tag->tagid; + else + cmd = HTML_UNKNOWN; + if (((obuf->flag & RB_XMPMODE) && cmd != HTML_N_XMP) || + ((obuf->flag & RB_LSTMODE) && cmd != HTML_N_LISTING)) { + Str tmp = Strdup(h_env->tagbuf); + Strcat_charp(tmp, str); + str = tmp->ptr; + goto read_as_plain; + } + if (cmd == HTML_UNKNOWN) + 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; + } + + read_as_plain: + mode = get_mctype(str); + delta = get_mclen(mode); + if (obuf->flag & (RB_SPECIAL & ~RB_NOBR)) { + if (*str != '\n') + obuf->flag &= ~RB_IGNORE_P; + if (*str == '\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 (*str == '\t') { + do { + PUSH(' '); + } while (obuf->pos % Tabstop != 0); + str++; + } + else if (obuf->flag & RB_PLAINMODE) { + char *p = htmlquote_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 != ' ') { + PUSH(' '); + } + str++; + } + else { +#ifdef JP_CHARSET + if (mode == PC_KANJI && + 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_KANJI && + Strlastchar(obuf->line) == ' ' && + obuf->pos >= h_env->envs[h_env->envc].indent) { + Strshrink(obuf->line, 1); + obuf->pos--; + } + } +#endif /* JP_CHARSET */ + 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_PREMODE | RB_NOBR | RB_INTXTA | RB_INSELECT + | RB_PLAINMODE | RB_IGNORE))) { + 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 */ + } + } +} + +static void +close_textarea(struct html_feed_environ *h_env) +{ + Str tmp; + + h_env->obuf->flag &= ~RB_INTXTA; + tmp = process_n_textarea(); + if (tmp != NULL) + HTMLlineproc1(tmp->ptr, h_env); +} + +extern char *NullLine; +extern Lineprop NullProp[]; + +static void +addnewline(Buffer * buf, char *line, Lineprop * prop, +#ifdef ANSI_COLOR + Linecolor * color, +#endif + int pos, int nlines) +{ + Line *l; + l = New(Line); + l->next = NULL; + if (pos > 0) { + l->lineBuf = allocStr(line, pos); + l->propBuf = New_N(Lineprop, pos); + bcopy((void *) prop, (void *) l->propBuf, pos * sizeof(Lineprop)); + } + else { + l->lineBuf = NullLine; + l->propBuf = NullProp; + } +#ifdef ANSI_COLOR + if (pos > 0 && color) { + l->colorBuf = New_N(Linecolor, pos); + bcopy((void *) color, (void *) l->colorBuf, pos * sizeof(Linecolor)); + } else { + l->colorBuf = NULL; + } +#endif + l->len = pos; + l->width = -1; + 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; + } + else { + l->real_linenumber = nlines; + } + l = NULL; +} + +/* + * 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) { + 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 (src) + fclose(src); + + return newBuf; +} + +static char *_size_unit[] = +{"b", "kb", "Mb", "Gb", "Tb", + "Pb", "Eb", "Zb", "Bb", "Yb", NULL}; + +char * +convert_size(int 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(int size1, int 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(int *linelen, int *trbyte) +{ + int i, j, rate, duration, eta, pos; + static time_t last_time, start_time; + time_t cur_time = time(0); + Str messages; + char *fmtrbyte, *fmrate; + + if (!fmInitialized) + return; + + if (current_content_length > 0) { + double ratio; + if (cur_time == last_time) + return; + last_time = cur_time; + if (*trbyte == 0) { + move(LASTLINE, 0); + clrtoeolx(); + start_time = cur_time; + } + *trbyte += *linelen; + *linelen = 0; + 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); +#if 0 /* def KANJI_SYMBOLS */ + for (j = pos; j <= i; j += 2) + addstr("¢£"); +#else /* not 0 */ + standout(); + addch(' '); + for (j = pos + 1; j <= i; j++) + addch('|'); + standend(); +#endif /* not 0 */ + /* no_clrtoeol(); */ + refresh(); + } + else if (*linelen > 1000) { + if (cur_time == last_time) + return; + last_time = cur_time; + if (*trbyte == 0) { + move(LASTLINE, 0); + clrtoeolx(); + start_time = cur_time; + } + *trbyte += *linelen; + *linelen = 0; + 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\n", fmtrbyte, fmrate); + } + else { + messages = Sprintf("%7s loaded\n", 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 = ' '; + obuf->flag = RB_IGNORE_P; + obuf->flag_sp = 0; + obuf->status = R_ST_NORMAL; + obuf->table_level = -1; + obuf->nobr_level = 0; + obuf->anchor = 0; + obuf->anchor_target = 0; + obuf->anchor_hseq = 0; + 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->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; + } + /* for unbalanced select tag */ + if (obuf->flag & RB_INSELECT) + HTMLlineproc1("</select>", h_env); + + /* for unbalanced table tag */ + while (obuf->table_level >= 0) { + table_mode[obuf->table_level].pre_mode + &= ~(TBLM_IGNORE | TBLM_XMP | TBLM_LST); + HTMLlineproc1("</table>", h_env); + } +} + +void +loadHTMLstream(URLFile * f, Buffer * newBuf, FILE * src, int internal) +{ + struct environment envs[MAX_ENV_LEVEL]; + int linelen = 0; + int trbyte = 0; + Str lineBuf2 = Strnew(); + char code; + struct html_feed_environ htmlenv1; + struct readbuffer obuf; + MySignalHandler(*prevtrap) (); + + if (SETJMP(AbortLoading) != 0) { + HTMLlineproc1("<br>Transfer Interrupted!<br>", &htmlenv1); + goto phase2; + } + if (fmInitialized) { + prevtrap = signal(SIGINT, KeyAbort); + term_cbreak(); + } + + n_textarea = 0; + cur_textarea = NULL; +#ifdef MENU_SELECT + n_select = 0; +#endif /* MENU_SELECT */ + cur_select = NULL; + form_sp = -1; +#ifdef NEW_FORM + form_max = -1; + forms_size = 0; + forms = NULL; +#endif /* NEW_FORM */ + + cur_hseq = 1; + + if (w3m_halfload) { + newBuf->buffername = "---"; +#ifdef JP_CHARSET + newBuf->document_code = InnerCode; +#endif /* JP_CHARSET */ + HTMLlineproc3(newBuf, f->stream); + w3m_halfload = FALSE; + if (fmInitialized) { + term_raw(); + signal(SIGINT, prevtrap); + } + return; + } + + init_henv(&htmlenv1, &obuf, envs, MAX_ENV_LEVEL, NULL, newBuf->width, 0); + + if (w3m_halfdump) + htmlenv1.f = stdout; + else + htmlenv1.buf = newTextLineList(); + +#ifdef JP_CHARSET + if (newBuf != NULL && newBuf->document_code != '\0') + code = newBuf->document_code; + else if (content_charset != '\0') + code = content_charset; + else + code = DocumentCode; + content_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) { + if (src) + Strfputs(lineBuf2, src); + linelen += lineBuf2->length; + showProgress(&linelen, &trbyte); +#ifdef JP_CHARSET + if (content_charset != '\0') { /* <META> */ + code = content_charset; + content_charset = '\0'; + } +#endif + if (!internal) + lineBuf2 = convertLine(f, lineBuf2, &code, HTML_MODE); +#ifdef USE_NNTP + if (f->scheme == SCM_NEWS) { + if (Str_news_endline(lineBuf2)) { + iseos(f->stream) = TRUE; + break; + } + } +#endif /* USE_NNTP */ + HTMLlineproc0(lineBuf2->ptr, &htmlenv1, internal); + } + if (obuf.status != R_ST_NORMAL) + HTMLlineproc1(correct_irrtag(obuf.status)->ptr, &htmlenv1); + 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) { + if (fmInitialized) { + term_raw(); + signal(SIGINT, prevtrap); + } + return; + } + phase2: + newBuf->trbyte = trbyte + linelen; + if (fmInitialized) { + term_raw(); + signal(SIGINT, prevtrap); + } + HTMLlineproc2(newBuf, htmlenv1.buf); +#ifdef JP_CHARSET + newBuf->document_code = code; +#endif /* JP_CHARSET */ +} + +/* + * loadHTMLString: read string and make new buffer + */ +Buffer * +loadHTMLString(Str page) +{ + URLFile f; + MySignalHandler(*prevtrap) (); + Buffer *newBuf; + + newBuf = newBuffer(INIT_BUFFER_WIDTH); + if (SETJMP(AbortLoading) != 0) { + discardBuffer(newBuf); + return NULL; + } + init_stream(&f, SCM_LOCAL, newStrStream(page)); + + if (fmInitialized) { + prevtrap = signal(SIGINT, KeyAbort); + term_cbreak(); + } + + loadHTMLstream(&f, newBuf, NULL, TRUE); + + if (fmInitialized) { + term_raw(); + signal(SIGINT, prevtrap); + } + newBuf->topLine = newBuf->firstLine; + newBuf->lastLine = newBuf->currentLine; + newBuf->currentLine = newBuf->firstLine; +#ifdef JP_CHARSET + newBuf->document_code = InnerCode; +#endif /* JP_CHARSET */ + + return newBuf; +} + +#ifdef USE_GOPHER + +/* + * loadGopherDir: get gopher directory + */ +Buffer * +loadGopherDir(URLFile * uf, Buffer * newBuf) +{ +#ifdef JP_CHARSET + char code, ic; +#endif + Str name, file, host, port; + char type; + char *p; + TextLineList *tl = newTextLineList(); + Str lbuf; + int hseq = 1; + + if (newBuf == NULL) + newBuf = newBuffer(INIT_BUFFER_WIDTH); +#ifdef JP_CHARSET + if (newBuf->document_code != '\0') + code = newBuf->document_code; + else if (content_charset != '\0') + code = content_charset; + else + code = DocumentCode; + content_charset = '\0'; +#endif + while (1) { + if (lbuf = StrUFgets(uf), lbuf->length == 0) + break; + if (lbuf->ptr[0] == '.' && + (lbuf->ptr[1] == '\n' || lbuf->ptr[1] == '\r')) + break; +#ifdef JP_CHARSET + if ((ic = checkShiftCode(lbuf, code)) != '\0') + lbuf = conv_str(lbuf, (code = ic), InnerCode); +#endif /* JP_CHARSET */ + cleanup_line(lbuf, HTML_MODE); + + p = lbuf->ptr; + for (name = Strnew(); *p && *p != '\t'; p++) + Strcat_char(name, *p); + p++; + for (file = Strnew(); *p && *p != '\t'; p++) + Strcat_char(file, *p); + p++; + for (host = Strnew(); *p && *p != '\t'; p++) + Strcat_char(host, *p); + p++; + for (port = Strnew(); *p && + *p != '\t' && *p != '\r' && *p != '\n'; + p++) + Strcat_char(port, *p); + p++; + type = name->ptr[0]; + switch (type) { + 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; + } + lbuf = Sprintf("<A HSEQ=\"%d\" HREF=\"gopher://", hseq++); + Strcat(lbuf, host); + Strcat_char(lbuf, ':'); + Strcat(lbuf, port); + Strcat_char(lbuf, '/'); + Strcat(lbuf, file); + Strcat_charp(lbuf, "\">"); + Strcat_charp(lbuf, p); + Strcat_charp(lbuf, name->ptr + 1); + pushTextLine(tl, newTextLine(lbuf, visible_length(lbuf->ptr))); + } + HTMLlineproc2(newBuf, tl); + newBuf->topLine = newBuf->firstLine; + newBuf->lastLine = newBuf->currentLine; + newBuf->currentLine = newBuf->firstLine; + + return newBuf; +} +#endif /* USE_GOPHER */ + +/* + * loadBuffer: read file and make new buffer + */ +Buffer * +loadBuffer(URLFile * uf, Buffer * newBuf) +{ + FILE *src = NULL; + char code; + Str lineBuf2; + char pre_lbuf = '\0'; + int nlines; + Str tmpf; + int linelen = 0, trbyte = 0; +#ifdef ANSI_COLOR + int check_color; +#endif + MySignalHandler(*prevtrap) (); + + if (newBuf == NULL) + newBuf = newBuffer(INIT_BUFFER_WIDTH); + lineBuf2 = Strnew(); + + if (SETJMP(AbortLoading) != 0) { + goto _end; + } + if (fmInitialized) { + prevtrap = signal(SIGINT, KeyAbort); + term_cbreak(); + } + + if (newBuf->sourcefile == NULL && uf->scheme != SCM_LOCAL) { + tmpf = tmpfname(TMPF_SRC, NULL); + src = fopen(tmpf->ptr, "w"); + if (src) + newBuf->sourcefile = tmpf->ptr; + } +#ifdef JP_CHARSET + if (newBuf->document_code != '\0') + code = newBuf->document_code; + else if (content_charset != '\0') + code = content_charset; + else + code = DocumentCode; + content_charset = '\0'; +#endif + + nlines = 0; + if (IStype(uf->stream) != IST_ENCODED) + uf->stream = newEncodedStream(uf->stream, uf->encoding); + while ((lineBuf2 = StrmyISgets(uf->stream))->length) { + if (src) + Strfputs(lineBuf2, src); + linelen += lineBuf2->length; + showProgress(&linelen, &trbyte); + lineBuf2 = convertLine(uf, lineBuf2, &code, PAGER_MODE); + if (squeezeBlankLine) { + if (lineBuf2->ptr[0] == '\n' && pre_lbuf == '\n') { + ++nlines; + continue; + } + pre_lbuf = lineBuf2->ptr[0]; + } + ++nlines; + if (showLineNum) { + Str tmp = Sprintf("%4d:", nlines); + Strcat(tmp, lineBuf2); + lineBuf2 = tmp; + } +#ifdef USE_NNTP + if (uf->scheme == SCM_NEWS) { + if (Str_news_endline(lineBuf2)) { + iseos(uf->stream) = TRUE; + break; + } + } +#endif /* USE_NNTP */ + Strchop(lineBuf2); + lineBuf2 = checkType(lineBuf2, propBuffer, +#ifdef ANSI_COLOR + colorBuffer, &check_color, +#endif + LINELEN); + addnewline(newBuf, lineBuf2->ptr, propBuffer, +#ifdef ANSI_COLOR + check_color ? colorBuffer : NULL, +#endif + lineBuf2->length, nlines); + } + _end: + if (fmInitialized) { + signal(SIGINT, prevtrap); + term_raw(); + } + newBuf->topLine = newBuf->firstLine; + newBuf->currentLine = newBuf->firstLine; + newBuf->trbyte = trbyte + linelen; +#ifdef JP_CHARSET + newBuf->document_code = code; +#endif /* JP_CHARSET */ + if (src) + fclose(src); + + return newBuf; +} + +/* + * saveBuffer: write buffer to file + */ + +void +saveBuffer(Buffer * buf, FILE * f) +{ + saveBufferDelNum(buf, f, FALSE); +} + +#ifndef KANJI_SYMBOLS +static Str +conv_rule(Line *l) +{ + Str tmp = NULL; + char *p = l->lineBuf, *ep = p + l->len; + Lineprop *pr = l->propBuf; + + for (; p < ep; p++, pr++) { + if (*pr & PC_RULE) { + if (tmp == NULL) { + tmp = Strnew_size(l->len); + Strcopy_charp_n(tmp, l->lineBuf, p - l->lineBuf); + } + Strcat_char(tmp, alt_rule[*p & 0xF]); + } else if (tmp != NULL) + Strcat_char(tmp, *p); + } + if (tmp) + return tmp; + else + return Strnew_charp_n(l->lineBuf, l->len); +} +#endif + +void +saveBufferDelNum(Buffer * buf, FILE * f, int del) +{ + Line *l = buf->firstLine; + Str tmp; + char *p; + +#ifndef KANJI_SYMBOLS + int is_html = FALSE; + + if (buf->type && ! strcasecmp(buf->type, "text/html")) + is_html = TRUE; +#endif + + pager_next: + for (; l != NULL; l = l->next) { +#ifndef KANJI_SYMBOLS + if (is_html) + tmp = conv_rule(l); + else +#endif + tmp = Strnew_charp_n(l->lineBuf, l->len); + if (del && (p = strchr(tmp->ptr, ':')) != NULL) + Strdelete(tmp, 0, p - tmp->ptr + 1); +#ifdef JP_CHARSET + tmp = conv_str(tmp, InnerCode, DisplayCode); +#endif + Strfputs(tmp, f); + if (Strlastchar(tmp) != '\n') + putc('\n', f); + } + if (buf->pagerSource && !(buf->bufferprop & BP_CLOSE)) { + l = getNextPage(buf, PagerMax); + goto pager_next; + } +} + +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); + if (buf == NULL) + return NULL; + return buf; +} + +/* + * getshell: execute shell command and get the result into a buffer + */ +Buffer * +getshell(char *cmd) +{ + Buffer *buf; + Str bn; + buf = loadcmdout(cmd, loadBuffer, NULL); + buf->filename = cmd; + bn = Sprintf("%s %s", SHELLBUFFERNAME, cmd); + buf->buffername = bn->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; + Str bn; + + 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; + bn = Sprintf("%s %s", PIPEBUFFERNAME, cmd); + buf->buffername = bn->ptr; + buf->bufferprop |= BP_PIPE; + 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; + buf->bufferprop |= BP_PIPE; +#ifdef JP_CHARSET + buf->document_code = DocumentCode; +#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 JP_CHARSET + 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 (!strcmp(t, "text/html")) { + buf = loadHTMLBuffer(&uf, t_buf); + buf->type = "text/html"; + } + else if (is_plain_text_type(t)) { + buf = openPagerBuffer(stream, t_buf); + buf->type = "text/plain"; + } + else { + if (doExternal(uf, "-", t, &buf, t_buf)) { + ; + } + else { /* unknown type is regarded as text/plain */ + buf = openPagerBuffer(stream, t_buf); + buf->type = "text/plain"; + } + } + buf->real_type = t; + buf->encoding = uf.encoding; + buf->currentURL.scheme = SCM_LOCAL; + buf->currentURL.file = "-"; + return buf; +} + +Line * +getNextPage(Buffer * buf, int plen) +{ + Line *l, *fl, *pl = buf->lastLine; + Line *rl = NULL; + int len, i, nlines = 0; + int linelen = buf->linelen, trbyte = buf->trbyte; + Str lineBuf2; + char pre_lbuf = '\0'; + URLFile uf; + char code; + int squeeze_flag = 0; +#ifdef ANSI_COLOR + int check_color; +#endif + + if (buf->pagerSource == NULL) + return NULL; + + if (fmInitialized) + crmode(); + if (pl != NULL) { + nlines = pl->real_linenumber; + pre_lbuf = *(pl->lineBuf); + if (showLineNum) { + char *p; + if ((p = strchr(pl->lineBuf, ':')) != NULL) + pre_lbuf = *(p + 1); + } + if (pre_lbuf == '\0') + pre_lbuf = '\n'; + } + +#ifdef JP_CHARSET + code = buf->document_code; +#endif + 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, buf->filename)->ptr; + else if (getenv("MAN_PN") == NULL) + buf->buffername = CPIPEBUFFERNAME; + buf->bufferprop |= BP_CLOSE; + trbyte += linelen; + linelen = 0; + break; + } + linelen += lineBuf2->length; + showProgress(&linelen, &trbyte); + lineBuf2 = convertLine(&uf, lineBuf2, &code, PAGER_MODE); + if (squeezeBlankLine) { + squeeze_flag = 0; + if (lineBuf2->ptr[0] == '\n' && pre_lbuf == '\n') { + ++nlines; + --i; + squeeze_flag = 1; + continue; + } + pre_lbuf = lineBuf2->ptr[0]; + } + ++nlines; + if (showLineNum) { + Str tmp = Sprintf("%4d:", nlines); + Strcat(tmp, lineBuf2); + lineBuf2 = tmp; + } + Strchop(lineBuf2); + lineBuf2 = checkType(lineBuf2, propBuffer, +#ifdef ANSI_COLOR + colorBuffer, &check_color, +#endif + LINELEN); + len = lineBuf2->length; + l = New(Line); + l->lineBuf = lineBuf2->ptr; + l->propBuf = New_N(Lineprop, len); + bcopy((void *) propBuffer, (void *) l->propBuf, len * sizeof(Lineprop)); +#ifdef ANSI_COLOR + if (check_color) { + l->colorBuf = New_N(Linecolor, len); + bcopy((void *) colorBuffer, (void *) l->colorBuf, len * sizeof(Linecolor)); + } else { + l->colorBuf = NULL; + } +#endif + l->len = len; + l->width = -1; + l->prev = pl; + if (squeezeBlankLine) { + l->real_linenumber = nlines; + l->linenumber = (pl == NULL ? nlines : pl->linenumber + 1); + } + else { + l->real_linenumber = l->linenumber = nlines; + } + if (pl == NULL) { + pl = l; + buf->firstLine = buf->topLine = buf->currentLine = l; + } + else { + pl->next = l; + pl = l; + } + if (rl == NULL) + rl = l; + if (nlines > PagerMax) { + fl = buf->firstLine; + buf->firstLine = fl->next; + fl->next->prev = NULL; + if (buf->topLine == fl) + buf->topLine = fl->next; + if (buf->currentLine == fl) + buf->currentLine = fl->next; + } + } + if (pl != NULL) + pl->next = NULL; + buf->lastLine = pl; + if (rl == NULL && squeeze_flag) { + rl = pl; + } + if (fmInitialized) + term_raw(); + buf->linelen = linelen; + buf->trbyte = trbyte; +#ifdef JP_CHARSET + buf->document_code = code; +#endif + return rl; +} + +static void +FTPhalfclose(InputStream stream) +{ + if (IStype(stream) == IST_FILE && file_of(stream)) { + Ftpfclose(file_of(stream)); + file_of(stream) = NULL; + } +} + +int +save2tmp(URLFile uf, char *tmpf) +{ + FILE *ff; + int check; + int linelen = 0, trbyte = 0; + MySignalHandler(*prevtrap) (); + 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; + } + if (fmInitialized) { + prevtrap = signal(SIGINT, KeyAbort); + term_cbreak(); + } + check = 0; + current_content_length = 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)); + if (fmInitialized) { + term_raw(); + signal(SIGINT, prevtrap); + } + fclose(ff); + if (uf.scheme == SCM_FTP) + FTPhalfclose(uf.stream); + return 0; +} + +int +doExternal(URLFile uf, char *path, char *type, Buffer **bufp, Buffer *defaultbuf) +{ + Str tmpf, command; + struct mailcap *mcap; + int stat; + Buffer *buf = NULL; + + if (!(mcap = searchExtViewer(type))) + return 0; + + tmpf = tmpfname(TMPF_DFL, NULL); + + if (mcap->nametemplate) { + Str tmp = unquote_mailcap(mcap->nametemplate, NULL, tmpf->ptr, NULL); + if (Strncmp(tmpf, tmp, tmpf->length) == 0) { + tmpf = tmp; + goto _save; + } + } + if (uf.ext && *uf.ext) { + Strcat_charp(tmpf, uf.ext); + } + _save: + if (save2tmp(uf, tmpf->ptr) < 0) + return 0; + command = unquote_mailcap(mcap->viewer, type, tmpf->ptr, &stat); +#ifndef __EMX__ + if (!(stat & MCSTAT_REPNAME)) { + Str tmp = Sprintf("(%s) < %s", command->ptr, tmpf->ptr); + command = tmp; + } +#endif + if (mcap->flags & (MAILCAP_HTMLOUTPUT|MAILCAP_COPIOUSOUTPUT)) { + if (defaultbuf == NULL) + defaultbuf = newBuffer(INIT_BUFFER_WIDTH); + defaultbuf->sourcefile = tmpf->ptr; + } + if (mcap->flags & MAILCAP_HTMLOUTPUT) { + buf = loadcmdout(command->ptr, loadHTMLBuffer, defaultbuf); + if (buf) + buf->type = "text/html"; + } + else if (mcap->flags & MAILCAP_COPIOUSOUTPUT) { + buf = loadcmdout(command->ptr, loadBuffer, defaultbuf); + if (buf) + buf->type = "text/plain"; + } + else { + if (mcap->flags & MAILCAP_NEEDSTERMINAL || !BackgroundExtViewer) { + fmTerm(); + mySystem(command->ptr, 0); + fmInit(); + if (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 = lastFileName(path); + buf->edit = mcap->edit; + } + *bufp = buf; + pushText(fileToDelete, tmpf->ptr); + return 1; +} + +static int +_MoveFile(char *path1, char *path2) +{ + InputStream f1; + FILE *f2; + int is_pipe; + int 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; +} + +void +doFileCopy(char *tmpf, char *defstr) +{ + Str msg; + char filen[256]; + char *p, *q; + + if (fmInitialized) { + p = searchKeyData(); + if (p == NULL || *p == '\0') { + p = inputLineHist("(Download)Save file to: ", + defstr, IN_COMMAND, SaveHist); + if (p == NULL || *p == '\0') + return; + } + if (*p != '|' || !PermitSaveToPipe) { + p = expandName(p); + if (checkOverWrite(p) < 0) + return; + } + if (checkCopyFile(tmpf, p) < 0) { + msg = Sprintf("Can't copy. %s and %s are identical.", tmpf, p); + disp_err_message(msg->ptr, FALSE); + return; + } + if (_MoveFile(tmpf, p) < 0) { + msg = Sprintf("Can't save to %s", p); + disp_err_message(msg->ptr, FALSE); + } + } + else { + q = searchKeyData(); + if (q == NULL || *q == '\0') { + printf("(Download)Save file to: "); + fflush(stdout); + p = fgets(filen, sizeof(filen), stdin); + if (p == NULL || filen[0] == '\0') + return; + q = filen; + } + for (p = q + strlen(q) - 1; IS_SPACE(*p); p--); + *(p + 1) = '\0'; + if (*q == '\0') + return; + p = q; + if (*p != '|' || !PermitSaveToPipe) { + p = expandName(p); + if (checkOverWrite(p) < 0) + return; + } + if (checkCopyFile(tmpf, p) < 0) { + printf("Can't copy. %s and %s are identical.", tmpf, p); + return; + } + if (_MoveFile(tmpf, p) < 0) { + printf("Can't save to %s\n", p); + } + } +} + +void +doFileMove(char *tmpf, char *defstr) +{ + doFileCopy(tmpf, defstr); + unlink(tmpf); +} + +void +doFileSave(URLFile uf, char *defstr) +{ + Str msg; + char filen[256]; + char *p, *q; + + if (fmInitialized) { + p = searchKeyData(); + if (p == NULL || *p == '\0') { + p = inputLineHist("(Download)Save file to: ", + defstr, IN_FILENAME, SaveHist); + if (p == NULL || *p == '\0') + return; + } + if (checkOverWrite(p) < 0) + return; + if (checkSaveFile(uf.stream, p) < 0) { + msg = Sprintf("Can't save. Load file and %s are identical.", p); + disp_err_message(msg->ptr, FALSE); + return; + } + if (save2tmp(uf, p) < 0) { + msg = Sprintf("Can't save to %s", p); + disp_err_message(msg->ptr, FALSE); + } + } + else { + q = searchKeyData(); + if (q == NULL || *q == '\0') { + printf("(Download)Save file to: "); + fflush(stdout); + p = fgets(filen, sizeof(filen), stdin); + if (p == NULL || filen[0] == '\0') + return; + q = filen; + } + for (p = q + strlen(q) - 1; IS_SPACE(*p); p--); + *(p + 1) = '\0'; + if (*q == '\0') + return; + p = expandName(q); + if (checkOverWrite(p) < 0) + return; + if (checkSaveFile(uf.stream, p) < 0) { + printf("Can't save. Load file and %s are identical.", p); + return; + } + if (save2tmp(uf, p) < 0) { + printf("Can't save to %s\n", p); + } + } +} + +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 buf[2]; + char *ans = NULL; + + if (stat(path, &st) < 0) + return 0; + if (fmInitialized) { + ans = inputStr("File exists. Overwrite? (y or n)", ""); + } + else { + printf("File exists. Overwrite? (y or n)"); + ans = fgets(buf, 2, stdin); + } + if (ans != NULL && (*ans == '\0' || tolower(*ans) == 'y')) + return 0; + else + return -1; +} + +static void +sig_chld(int signo) +{ + int stat; +#ifdef HAVE_WAITPID + pid_t pid; + + while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) { + ; + } +#elif HAVE_WAIT3 + int pid; + + while ((pid = wait3(&stat, WNOHANG, NULL)) > 0) { + ; + } +#else + wait(&stat); +#endif + return; +} + +#ifdef __EMX__ +#define GUNZIP_CMD "gzip" +#define BUNZIP2_CMD "bzip2" +#else /* not __EMX__ */ +#define GUNZIP_CMD "gunzip" +#define BUNZIP2_CMD "bunzip2" +#endif /* not __EMX__ */ +#define INFLATE_CMD "inflate" +#define GUNZIP_NAME "gunzip" +#define BUNZIP2_NAME "bunzip2" +#define INFLATE_NAME "inflate" + +void +gunzip_stream(URLFile *uf) +{ + int pid1; + int fd1[2]; + char *expand_cmd = GUNZIP_CMD; + char *expand_name = GUNZIP_NAME; + char *tmpf = NULL; + + switch (uf->compression) { + case CMP_COMPRESS: + case CMP_GZIP: + expand_cmd = GUNZIP_CMD; + expand_name = GUNZIP_NAME; + break; + case CMP_BZIP2: + expand_cmd = BUNZIP2_CMD; + expand_name = BUNZIP2_NAME; + break; + case CMP_DEFLATE: + expand_cmd = INFLATE_CMD; + expand_name = INFLATE_NAME; + break; + } + uf->compression = CMP_NOCOMPRESS; + + if (pipe(fd1) < 0) { + UFclose(uf); + return; + } + + if (uf->scheme != SCM_HTTP && uf->scheme != SCM_LOCAL) { + tmpf = tmpfname(TMPF_DFL, NULL)->ptr; + if (save2tmp(*uf, tmpf) < 0) { + UFclose(uf); + return; + } + if (uf->scheme != SCM_FTP) + UFclose(uf); + pushText(fileToDelete, tmpf); + } + +#ifdef SIGCHLD + signal(SIGCHLD, sig_chld); +#endif + flush_tty(); + /* fd1[0]: read, fd1[1]: write */ + if ((pid1 = fork()) == 0) { + signal(SIGINT, SIG_DFL); + close(fd1[0]); + if (tmpf) { +#ifdef __CYGWIN__ + int tmpfd = open(tmpf, O_RDONLY|O_BINARY); +#else + int tmpfd = open(tmpf, O_RDONLY); +#endif + if (tmpfd < 0) { + close(fd1[1]); + exit(1); + } + dup2(tmpfd, 0); + } + else { + /* child */ + int pid2; + int fd2[2]; +#ifdef SIGCHLD + signal(SIGCHLD, sig_chld); +#endif + if (fmInitialized) { + close_tty(); + fmInitialized = FALSE; + } + if (pipe(fd2) < 0) { + close(fd1[1]); + UFclose(uf); + exit(1); + } + if ((pid2 = fork()) == 0) { + /* child */ + Str buf = Strnew_size(SAVE_BUF_SIZE); + close(fd2[0]); + while (UFread(uf, buf, SAVE_BUF_SIZE)) { + if (write(fd2[1], buf->ptr, buf->length) < 0) { + close(fd2[1]); + exit(0); + } + } + close(fd2[1]); + exit(0); + } + close(fd2[1]); + dup2(fd2[0], 0); + } + dup2(fd1[1], 1); + execlp(expand_cmd, expand_name, NULL); + exit(0); + } + close(fd1[1]); + if (tmpf == NULL) + UFclose(uf); + uf->stream = newFileStream(fdopen(fd1[0], "rb"), (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, 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->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; + if (!strcasecmp(buf->type, "text/html")) + loadHTMLBuffer(&uf, buf); + else + loadBuffer(&uf, buf); + UFclose(&uf); + is_redisplay = FALSE; +} +#endif + +#ifdef JP_CHARSET +static char +guess_charset(char *p) +{ + Str c = Strnew_size(strlen(p)); + if (strncasecmp(p, "x-", 2) == 0) + p += 2; + while (*p != '\0') { + if (*p != '-' && *p != '_') + Strcat_char(c, tolower(*p)); + p++; + } + if (strncmp(c->ptr, "euc", 3) == 0) + return CODE_EUC; + if (strncmp(c->ptr, "shiftjis", 8) == 0 || + strncmp(c->ptr, "sjis", 4) == 0) + return CODE_SJIS; + if (strncmp(c->ptr, "iso2022jp", 9) == 0 || + strncmp(c->ptr, "jis", 3) == 0) + return CODE_JIS_n; + return CODE_ASCII; +} +#endif + +char * +guess_save_name(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; +} + +/* Local Variables: */ +/* c-basic-offset: 4 */ +/* tab-width: 8 */ +/* End: */ |