diff options
Diffstat (limited to '')
-rw-r--r-- | debian/patches/240_win64gc.patch | 1235 |
1 files changed, 1235 insertions, 0 deletions
diff --git a/debian/patches/240_win64gc.patch b/debian/patches/240_win64gc.patch new file mode 100644 index 0000000..5005155 --- /dev/null +++ b/debian/patches/240_win64gc.patch @@ -0,0 +1,1235 @@ +Subject: Workaround of GC crash on Cygwin64 +From: AIDA Shinra <shinra@j10n.org> +Origin: http://www.j10n.org/files/w3m-cvs-1.1055-win64gc.patch + + Patch from [w3m-dev:04469] on 2013-10-14. + +diff --git a/config.h.in b/config.h.in +index 59997b4..a4110ea 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -210,6 +210,10 @@ typedef RETSIGTYPE MySignalHandler; + #define SUPPORT_WIN9X_CONSOLE_MBCS 1 + #endif + ++#if defined(__CYGWIN__) && defined(__x86_64__) ++#define DONT_CALL_GC_AFTER_FORK ++#endif ++ + #if defined(__DJGPP__) + #define DEFAULT_TERM "dosansi" + #else +diff --git a/file.c b/file.c +index 89c9152..6f4d5b8 100644 +--- a/file.c ++++ b/file.c +@@ -677,6 +677,7 @@ readHeader(URLFile *uf, Buffer *newBuf, int thru, ParsedURL *pu) + #endif + init_stream(&f, SCM_LOCAL, newStrStream(src)); + loadHTMLstream(&f, newBuf, NULL, TRUE); ++ UFclose(&f); + for (l = newBuf->lastLine; l && l->real_linenumber; + l = l->prev) + l->real_linenumber = 0; +@@ -7238,16 +7239,17 @@ loadHTMLString(Str page) + MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL; + Buffer *newBuf; + ++ init_stream(&f, SCM_LOCAL, newStrStream(page)); ++ + newBuf = newBuffer(INIT_BUFFER_WIDTH); + if (SETJMP(AbortLoading) != 0) { + TRAP_OFF; + discardBuffer(newBuf); ++ UFclose(&f); + return NULL; + } + TRAP_ON; + +- init_stream(&f, SCM_LOCAL, newStrStream(page)); +- + #ifdef USE_M17N + newBuf->document_charset = InnerCharset; + #endif +@@ -7257,6 +7259,7 @@ loadHTMLString(Str page) + #endif + + TRAP_OFF; ++ UFclose(&f); + newBuf->topLine = newBuf->firstLine; + newBuf->lastLine = newBuf->currentLine; + newBuf->currentLine = newBuf->firstLine; +@@ -7486,15 +7489,13 @@ loadImageBuffer(URLFile *uf, Buffer *newBuf) + !stat(cache->file, &st)) + goto image_buffer; + +- TRAP_ON; + if (IStype(uf->stream) != IST_ENCODED) + uf->stream = newEncodedStream(uf->stream, uf->encoding); ++ TRAP_ON; + if (save2tmp(*uf, cache->file) < 0) { +- UFclose(uf); + TRAP_OFF; + return NULL; + } +- UFclose(uf); + TRAP_OFF; + + cache->loaded = IMG_FLAG_LOADED; +@@ -7514,6 +7515,7 @@ loadImageBuffer(URLFile *uf, Buffer *newBuf) + + init_stream(&f, SCM_LOCAL, newStrStream(tmp)); + loadHTMLstream(&f, newBuf, src, TRUE); ++ UFclose(&f); + if (src) + fclose(src); + +@@ -7909,6 +7911,8 @@ save2tmp(URLFile uf, char *tmpf) + clen_t linelen = 0, trbyte = 0; + MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL; + static JMP_BUF env_bak; ++ volatile int retval = 0; ++ char *volatile buf = NULL; + + ff = fopen(tmpf, "wb"); + if (ff == NULL) { +@@ -7945,25 +7949,25 @@ save2tmp(URLFile uf, char *tmpf) + else + #endif /* USE_NNTP */ + { +- Str buf = Strnew_size(SAVE_BUF_SIZE); +- while (UFread(&uf, buf, SAVE_BUF_SIZE)) { +- if (Strfputs(buf, ff) != buf->length) { +- bcopy(env_bak, AbortLoading, sizeof(JMP_BUF)); +- TRAP_OFF; +- fclose(ff); +- current_content_length = 0; +- return -2; ++ int count; ++ ++ buf = NewWithoutGC_N(char, SAVE_BUF_SIZE); ++ while ((count = ISread_n(uf.stream, buf, SAVE_BUF_SIZE)) > 0) { ++ if (fwrite(buf, 1, count, ff) != count) { ++ retval = -2; ++ goto _end; + } +- linelen += buf->length; ++ linelen += count; + showProgress(&linelen, &trbyte); + } + } + _end: + bcopy(env_bak, AbortLoading, sizeof(JMP_BUF)); + TRAP_OFF; ++ xfree(buf); + fclose(ff); + current_content_length = 0; +- return 0; ++ return retval; + } + + Buffer * +@@ -8074,7 +8078,8 @@ _MoveFile(char *path1, char *path2) + FILE *f2; + int is_pipe; + clen_t linelen = 0, trbyte = 0; +- Str buf; ++ char *buf = NULL; ++ int count; + + f1 = openIS(path1); + if (f1 == NULL) +@@ -8092,12 +8097,13 @@ _MoveFile(char *path1, char *path2) + 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; ++ buf = NewWithoutGC_N(char, SAVE_BUF_SIZE); ++ while ((count = ISread_n(f1, buf, SAVE_BUF_SIZE)) > 0) { ++ fwrite(buf, 1, count, f2); ++ linelen += count; + showProgress(&linelen, &trbyte); + } ++ xfree(buf); + ISclose(f1); + if (is_pipe) + pclose(f2); +@@ -8456,21 +8462,23 @@ uncompress_stream(URLFile *uf, char **src) + } + if (pid2 == 0) { + /* child2 */ +- Str buf = Strnew_size(SAVE_BUF_SIZE); ++ char *buf = NewWithoutGC_N(char, SAVE_BUF_SIZE); ++ int count; + FILE *f = NULL; + + setup_child(TRUE, 2, UFfileno(uf)); + if (tmpf) + f = fopen(tmpf, "wb"); +- while (UFread(uf, buf, SAVE_BUF_SIZE)) { +- if (Strfputs(buf, stdout) < 0) ++ while ((count = ISread_n(uf->stream, buf, SAVE_BUF_SIZE)) > 0) { ++ if (fwrite(buf, 1, count, stdout) != count) ++ break; ++ if (f && fwrite(buf, 1, count, f) != count) + break; +- if (f) +- Strfputs(buf, f); + } + UFclose(uf); + if (f) + fclose(f); ++ xfree(buf); + exit(0); + } + /* child1 */ +diff --git a/fm.h b/fm.h +index acdab46..2216b06 100644 +--- a/fm.h ++++ b/fm.h +@@ -76,6 +76,7 @@ typedef int wc_ces; /* XXX: not used */ + #include "textlist.h" + #include "funcname1.h" + #include "terms.h" ++#include "istream.h" + + #ifndef HAVE_BCOPY + void bcopy(const void *, void *, int); +@@ -288,8 +289,6 @@ extern int REV_LB[]; + #define inputFilenameHist(p,d,h) inputLineHist(p,d,IN_FILENAME,h) + #define inputChar(p) inputLine(p,"",IN_CHAR) + +-#define free(x) GC_free(x) /* let GC do it. */ +- + #ifdef __EMX__ + #define HAVE_STRCASECMP + #define strcasecmp stricmp +@@ -895,6 +894,9 @@ global char *index_file init(NULL); + + global char *CurrentDir; + global int CurrentPid; ++#if defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) ++global char *MyProgramName init("w3m"); ++#endif /* defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) */ + /* + * global Buffer *Currentbuf; + * global Buffer *Firstbuf; +diff --git a/html.h b/html.h +index 4a2827b..b4b3df9 100644 +--- a/html.h ++++ b/html.h +@@ -1,19 +1,17 @@ + /* $Id: html.h,v 1.31 2010/08/14 01:29:40 htrb Exp $ */ + #ifndef _HTML_H + #define _HTML_H ++#include "config.h" + #ifdef USE_SSL + #include <openssl/bio.h> + #include <openssl/x509.h> + #include <openssl/ssl.h> + #endif /* USE_SSL */ + +-#include "istream.h" +- + #define StrUFgets(f) StrISgets((f)->stream) + #define StrmyUFgets(f) StrmyISgets((f)->stream) + #define UFgetc(f) ISgetc((f)->stream) + #define UFundogetc(f) ISundogetc((f)->stream) +-#define UFread(f,buf,len) ISread((f)->stream,buf,len) + #define UFclose(f) (void)(ISclose((f)->stream) == 0 && ((f)->stream = NULL)) + #define UFfileno(f) ISfileno((f)->stream) + +@@ -62,11 +60,12 @@ typedef struct _ParsedURL { + int is_nocache; + } ParsedURL; + ++union input_stream; + typedef struct { + unsigned char scheme; + char is_cgi; + char encoding; +- InputStream stream; ++ union input_stream *stream; + char *ext; + int compression; + int content_encoding; +diff --git a/image.c b/image.c +index 5f5991a..9d0e9b5 100644 +--- a/image.c ++++ b/image.c +@@ -90,17 +90,18 @@ termImage() + static int + openImgdisplay() + { ++ char *cmd; ++ ++ if (!strchr(Imgdisplay, '/')) ++ cmd = Strnew_m_charp(w3m_auxbin_dir(), "/", Imgdisplay, NULL)->ptr; ++ else ++ cmd = Imgdisplay; + Imgdisplay_pid = open_pipe_rw(&Imgdisplay_rf, &Imgdisplay_wf); + if (Imgdisplay_pid < 0) + goto err0; + if (Imgdisplay_pid == 0) { + /* child */ +- char *cmd; + setup_child(FALSE, 2, -1); +- if (!strchr(Imgdisplay, '/')) +- cmd = Strnew_m_charp(w3m_auxbin_dir(), "/", Imgdisplay, NULL)->ptr; +- else +- cmd = Imgdisplay; + myExec(cmd); + /* XXX: ifdef __EMX__, use start /f ? */ + } +@@ -333,6 +334,9 @@ loadImage(Buffer *buf, int flag) + struct stat st; + int i, draw = FALSE; + /* int wait_st; */ ++#ifdef DONT_CALL_GC_AFTER_FORK ++ char *loadargs[7]; ++#endif + + if (maxLoadImage > MAX_LOAD_IMAGE) + maxLoadImage = MAX_LOAD_IMAGE; +@@ -433,6 +437,24 @@ loadImage(Buffer *buf, int flag) + image_cache[i] = cache; + + flush_tty(); ++#ifdef DONT_CALL_GC_AFTER_FORK ++ loadargs[0] = MyProgramName; ++ loadargs[1] = "-$$getimage"; ++ loadargs[2] = conv_to_system(cache->url); ++ loadargs[3] = conv_to_system(parsedURL2Str(cache->current)->ptr); ++ loadargs[4] = cache->file; ++ loadargs[5] = cache->touch; ++ loadargs[6] = NULL; ++ if ((cache->pid = fork()) == 0) { ++ setup_child(FALSE, 0, -1); ++ execvp(MyProgramName, loadargs); ++ exit(1); ++ } ++ else if (cache->pid < 0) { ++ cache->pid = 0; ++ return; ++ } ++#else /* !DONT_CALL_GC_AFTER_FORK */ + if ((cache->pid = fork()) == 0) { + Buffer *b; + /* +@@ -458,6 +480,7 @@ loadImage(Buffer *buf, int flag) + cache->pid = 0; + return; + } ++#endif /* !DONT_CALL_GC_AFTER_FORK */ + } + } + +diff --git a/indep.c b/indep.c +index 89e86c1..5c5de06 100644 +--- a/indep.c ++++ b/indep.c +@@ -721,6 +721,111 @@ shell_quote(char *str) + return str; + } + ++void * ++xrealloc(void *ptr, size_t size) ++{ ++ void *newptr = realloc(ptr, size); ++ if (newptr == NULL) { ++ fprintf(stderr, "Out of memory\n"); ++ exit(-1); ++ } ++ return newptr; ++} ++ ++/* Define this as a separate function in case the free() has ++ * an incompatible prototype. */ ++void ++xfree(void *ptr) ++{ ++ free(ptr); ++} ++ ++void * ++w3m_GC_realloc_atomic(void *ptr, size_t size) ++{ ++ return ptr ? GC_REALLOC(ptr, size) : GC_MALLOC_ATOMIC(size); ++} ++ ++void ++w3m_GC_free(void *ptr) ++{ ++ GC_FREE(ptr); ++} ++ ++void ++growbuf_init(struct growbuf *gb) ++{ ++ gb->ptr = NULL; ++ gb->length = 0; ++ gb->area_size = 0; ++ gb->realloc_proc = &w3m_GC_realloc_atomic; ++ gb->free_proc = &w3m_GC_free; ++} ++ ++void ++growbuf_init_without_GC(struct growbuf *gb) ++{ ++ gb->ptr = NULL; ++ gb->length = 0; ++ gb->area_size = 0; ++ gb->realloc_proc = &xrealloc; ++ gb->free_proc = &xfree; ++} ++ ++void ++growbuf_clear(struct growbuf *gb) ++{ ++ (*gb->free_proc) (gb->ptr); ++ gb->ptr = NULL; ++ gb->length = 0; ++ gb->area_size = 0; ++} ++ ++Str ++growbuf_to_Str(struct growbuf *gb) ++{ ++ Str s; ++ ++ if (gb->free_proc == &w3m_GC_free) { ++ growbuf_reserve(gb, gb->length + 1); ++ gb->ptr[gb->length] = '\0'; ++ s = New(struct _Str); ++ s->ptr = gb->ptr; ++ s->length = gb->length; ++ s->area_size = gb->area_size; ++ } else { ++ s = Strnew_charp_n(gb->ptr, gb->length); ++ (*gb->free_proc) (gb->ptr); ++ } ++ gb->ptr = NULL; ++ gb->length = 0; ++ gb->area_size = 0; ++ return s; ++} ++ ++void ++growbuf_reserve(struct growbuf *gb, int leastarea) ++{ ++ int newarea; ++ ++ if (gb->area_size < leastarea) { ++ newarea = gb->area_size * 3 / 2; ++ if (newarea < leastarea) ++ newarea = leastarea; ++ newarea += 16; ++ gb->ptr = (*gb->realloc_proc) (gb->ptr, newarea); ++ gb->area_size = newarea; ++ } ++} ++ ++void ++growbuf_append(struct growbuf *gb, const char *src, int len) ++{ ++ growbuf_reserve(gb, gb->length + len); ++ memcpy(&gb->ptr[gb->length], src, len); ++ gb->length += len; ++} ++ + static char * + w3m_dir(const char *name, char *dft) + { +diff --git a/indep.h b/indep.h +index cf566fe..84416ed 100644 +--- a/indep.h ++++ b/indep.h +@@ -12,6 +12,14 @@ + #define FALSE 0 + #endif /* FALSE */ + ++struct growbuf { ++ char *ptr; ++ int length; ++ int area_size; ++ void *(*realloc_proc) (void *, size_t); ++ void (*free_proc) (void *); ++}; ++ + #define RAW_MODE 0 + #define PAGER_MODE 1 + #define HTML_MODE 2 +@@ -65,6 +73,18 @@ extern Str Str_url_unquote(Str x, int is_form, int safe); + extern Str Str_form_quote(Str x); + #define Str_form_unquote(x) Str_url_unquote((x), TRUE, FALSE) + extern char *shell_quote(char *str); ++#define xmalloc(s) xrealloc(NULL, s) ++extern void *xrealloc(void *ptr, size_t size); ++extern void xfree(void *ptr); ++extern void *w3m_GC_realloc_atomic(void *ptr, size_t size); ++extern void w3m_GC_free(void *ptr); ++extern void growbuf_init(struct growbuf *gb); ++extern void growbuf_init_without_GC(struct growbuf *gb); ++extern void growbuf_clear(struct growbuf *gb); ++extern Str growbuf_to_Str(struct growbuf *gb); ++extern void growbuf_reserve(struct growbuf *gb, int leastarea); ++extern void growbuf_append(struct growbuf *gb, const char *src, int len); ++#define GROWBUF_ADD_CHAR(gb,ch) ((((gb)->length>=(gb)->area_size)?growbuf_reserve(gb,(gb)->length+1):(void)0),(void)((gb)->ptr[(gb)->length++] = (ch))) + + extern char *w3m_auxbin_dir(); + extern char *w3m_lib_dir(); +@@ -77,5 +97,8 @@ extern char *w3m_help_dir(); + #define New_N(type,n) ((type*)GC_MALLOC((n)*sizeof(type))) + #define NewAtom_N(type,n) ((type*)GC_MALLOC_ATOMIC((n)*sizeof(type))) + #define New_Reuse(type,ptr,n) ((type*)GC_REALLOC((ptr),(n)*sizeof(type))) ++#define NewWithoutGC(type) ((type*)xmalloc(sizeof(type))) ++#define NewWithoutGC_N(type,n) ((type*)xmalloc((n)*sizeof(type))) ++#define NewWithoutGC_Reuse(type,ptr,n) ((type*)xrealloc(ptr,(n)*sizeof(type))) + + #endif /* INDEP_H */ +diff --git a/istream.c b/istream.c +index d8c8e45..3126142 100644 +--- a/istream.c ++++ b/istream.c +@@ -35,12 +35,14 @@ static int ssl_read(struct ssl_handle *handle, char *buf, int len); + static int ens_read(struct ens_handle *handle, char *buf, int len); + static void ens_close(struct ens_handle *handle); + ++static void memchop(char *p, int *len); ++ + static void + do_update(BaseStream base) + { + int len; + base->stream.cur = base->stream.next = 0; +- len = base->read(base->handle, base->stream.buf, base->stream.size); ++ len = (*base->read) (base->handle, base->stream.buf, base->stream.size); + if (len <= 0) + base->iseos = TRUE; + else +@@ -66,12 +68,12 @@ init_buffer(BaseStream base, char *buf, int bufsize) + StreamBuffer sb = &base->stream; + sb->size = bufsize; + sb->cur = 0; ++ sb->buf = NewWithoutGC_N(uchar, bufsize); + if (buf) { +- sb->buf = (uchar *) buf; ++ memcpy(sb->buf, buf, bufsize); + sb->next = bufsize; + } + else { +- sb->buf = NewAtom_N(uchar, bufsize); + sb->next = 0; + } + base->iseos = FALSE; +@@ -95,10 +97,10 @@ newInputStream(int des) + InputStream stream; + if (des < 0) + return NULL; +- stream = New(union input_stream); ++ stream = NewWithoutGC(union input_stream); + init_base_stream(&stream->base, STREAM_BUF_SIZE); + stream->base.type = IST_BASIC; +- stream->base.handle = New(int); ++ stream->base.handle = NewWithoutGC(int); + *(int *)stream->base.handle = des; + stream->base.read = (int (*)())basic_read; + stream->base.close = (void (*)())basic_close; +@@ -111,10 +113,10 @@ newFileStream(FILE * f, void (*closep) ()) + InputStream stream; + if (f == NULL) + return NULL; +- stream = New(union input_stream); ++ stream = NewWithoutGC(union input_stream); + init_base_stream(&stream->base, STREAM_BUF_SIZE); + stream->file.type = IST_FILE; +- stream->file.handle = New(struct io_file_handle); ++ stream->file.handle = NewWithoutGC(struct io_file_handle); + stream->file.handle->f = f; + if (closep) + stream->file.handle->close = closep; +@@ -131,10 +133,10 @@ newStrStream(Str s) + InputStream stream; + if (s == NULL) + return NULL; +- stream = New(union input_stream); ++ stream = NewWithoutGC(union input_stream); + init_str_stream(&stream->base, s); + stream->str.type = IST_STR; +- stream->str.handle = s; ++ stream->str.handle = NULL; + stream->str.read = (int (*)())str_read; + stream->str.close = NULL; + return stream; +@@ -147,10 +149,10 @@ newSSLStream(SSL * ssl, int sock) + InputStream stream; + if (sock < 0) + return NULL; +- stream = New(union input_stream); ++ stream = NewWithoutGC(union input_stream); + init_base_stream(&stream->base, SSL_BUF_SIZE); + stream->ssl.type = IST_SSL; +- stream->ssl.handle = New(struct ssl_handle); ++ stream->ssl.handle = NewWithoutGC(struct ssl_handle); + stream->ssl.handle->ssl = ssl; + stream->ssl.handle->sock = sock; + stream->ssl.read = (int (*)())ssl_read; +@@ -166,14 +168,14 @@ newEncodedStream(InputStream is, char encoding) + if (is == NULL || (encoding != ENC_QUOTE && encoding != ENC_BASE64 && + encoding != ENC_UUENCODE)) + return is; +- stream = New(union input_stream); ++ stream = NewWithoutGC(union input_stream); + init_base_stream(&stream->base, STREAM_BUF_SIZE); + stream->ens.type = IST_ENCODED; +- stream->ens.handle = New(struct ens_handle); ++ stream->ens.handle = NewWithoutGC(struct ens_handle); + stream->ens.handle->is = is; + stream->ens.handle->pos = 0; + stream->ens.handle->encoding = encoding; +- stream->ens.handle->s = NULL; ++ growbuf_init_without_GC(&stream->ens.handle->gb); + stream->ens.read = (int (*)())ens_read; + stream->ens.close = (void (*)())ens_close; + return stream; +@@ -187,8 +189,10 @@ ISclose(InputStream stream) + stream->base.type & IST_UNCLOSE) + return -1; + prevtrap = mySignal(SIGINT, SIG_IGN); +- stream->base.close(stream->base.handle); ++ stream->base.close (stream->base.handle); + mySignal(SIGINT, prevtrap); ++ xfree(stream->base.stream.buf); ++ xfree(stream); + return 0; + } + +@@ -218,122 +222,97 @@ ISundogetc(InputStream stream) + return -1; + } + +-#define MARGIN_STR_SIZE 10 + Str +-StrISgets(InputStream stream) ++StrISgets2(InputStream stream, char crnl) + { +- BaseStream base; +- StreamBuffer sb; +- Str s = NULL; +- uchar *p; +- int len; ++ struct growbuf gb; + + if (stream == NULL) +- return '\0'; +- base = &stream->base; +- sb = &base->stream; +- +- while (!base->iseos) { +- if (MUST_BE_UPDATED(base)) { +- do_update(base); +- } +- else { +- if ((p = memchr(&sb->buf[sb->cur], '\n', sb->next - sb->cur))) { +- len = p - &sb->buf[sb->cur] + 1; +- if (s == NULL) +- s = Strnew_size(len); +- Strcat_charp_n(s, (char *)&sb->buf[sb->cur], len); +- sb->cur += len; +- return s; +- } +- else { +- if (s == NULL) +- s = Strnew_size(sb->next - sb->cur + MARGIN_STR_SIZE); +- Strcat_charp_n(s, (char *)&sb->buf[sb->cur], +- sb->next - sb->cur); +- sb->cur = sb->next; +- } +- } +- } +- +- if (s == NULL) +- return Strnew(); +- return s; ++ return NULL; ++ growbuf_init(&gb); ++ ISgets_to_growbuf(stream, &gb, crnl); ++ return growbuf_to_Str(&gb); + } + +-Str +-StrmyISgets(InputStream stream) ++void ++ISgets_to_growbuf(InputStream stream, struct growbuf *gb, char crnl) + { +- BaseStream base; +- StreamBuffer sb; +- Str s = NULL; +- int i, len; ++ BaseStream base = &stream->base; ++ StreamBuffer sb = &base->stream; ++ int i; + +- if (stream == NULL) +- return '\0'; +- base = &stream->base; +- sb = &base->stream; ++ gb->length = 0; + + while (!base->iseos) { + if (MUST_BE_UPDATED(base)) { + do_update(base); ++ continue; + } +- else { +- if (s && Strlastchar(s) == '\r') { +- if (sb->buf[sb->cur] == '\n') +- Strcat_char(s, (char)sb->buf[sb->cur++]); +- return s; ++ if (crnl && gb->length > 0 && gb->ptr[gb->length - 1] == '\r') { ++ if (sb->buf[sb->cur] == '\n') { ++ GROWBUF_ADD_CHAR(gb, '\n'); ++ ++sb->cur; + } +- for (i = sb->cur; +- i < sb->next && sb->buf[i] != '\n' && sb->buf[i] != '\r'; +- i++) ; +- if (i < sb->next) { +- len = i - sb->cur + 1; +- if (s == NULL) +- s = Strnew_size(len + MARGIN_STR_SIZE); +- Strcat_charp_n(s, (char *)&sb->buf[sb->cur], len); +- sb->cur = i + 1; +- if (sb->buf[i] == '\n') +- return s; +- } +- else { +- if (s == NULL) +- s = Strnew_size(sb->next - sb->cur + MARGIN_STR_SIZE); +- Strcat_charp_n(s, (char *)&sb->buf[sb->cur], +- sb->next - sb->cur); +- sb->cur = sb->next; ++ break; ++ } ++ for (i = sb->cur; i < sb->next; ++i) { ++ if (sb->buf[i] == '\n' || (crnl && sb->buf[i] == '\r')) { ++ ++i; ++ break; + } + } ++ growbuf_append(gb, &sb->buf[sb->cur], i - sb->cur); ++ sb->cur = i; ++ if (gb->length > 0 && gb->ptr[gb->length - 1] == '\n') ++ break; + } + +- if (s == NULL) +- return Strnew(); +- return s; ++ growbuf_reserve(gb, gb->length + 1); ++ gb->ptr[gb->length] = '\0'; ++ return; + } + ++#ifdef unused + int + ISread(InputStream stream, Str buf, int count) + { +- int rest, len; ++ int len; ++ ++ if (count + 1 > buf->area_size) { ++ char *newptr = GC_MALLOC_ATOMIC(count + 1); ++ memcpy(newptr, buf->ptr, buf->length); ++ newptr[buf->length] = '\0'; ++ buf->ptr = newptr; ++ buf->area_size = count + 1; ++ } ++ len = ISread_n(stream, buf->ptr, count); ++ buf->length = (len > 0) ? len : 0; ++ buf->ptr[buf->length] = '\0'; ++ return (len > 0) ? 1 : 0; ++} ++#endif ++ ++int ++ISread_n(InputStream stream, char *dst, int count) ++{ ++ int len, l; + BaseStream base; + +- if (stream == NULL || (base = &stream->base)->iseos) ++ if (stream == NULL || count <= 0) ++ return -1; ++ if ((base = &stream->base)->iseos) + return 0; + +- len = buffer_read(&base->stream, buf->ptr, count); +- rest = count - len; ++ len = buffer_read(&base->stream, dst, count); + if (MUST_BE_UPDATED(base)) { +- len = base->read(base->handle, &buf->ptr[len], rest); +- if (len <= 0) { ++ l = (*base->read) (base->handle, &dst[len], count - len); ++ if (l <= 0) { + base->iseos = TRUE; +- len = 0; ++ } else { ++ len += l; + } +- rest -= len; + } +- Strtruncate(buf, count - rest); +- if (buf->length > 0) +- return 1; +- return 0; ++ return len; + } + + int +@@ -645,6 +624,7 @@ basic_close(int *handle) + #else + close(*(int *)handle); + #endif ++ xfree(handle); + } + + static int +@@ -661,6 +641,7 @@ static void + file_close(struct io_file_handle *handle) + { + handle->close(handle->f); ++ xfree(handle); + } + + static int +@@ -682,6 +663,7 @@ ssl_close(struct ssl_handle *handle) + close(handle->sock); + if (handle->ssl) + SSL_free(handle->ssl); ++ xfree(handle); + } + + static int +@@ -717,38 +699,60 @@ static void + ens_close(struct ens_handle *handle) + { + ISclose(handle->is); ++ growbuf_clear(&handle->gb); ++ xfree(handle); + } + + static int + ens_read(struct ens_handle *handle, char *buf, int len) + { +- if (handle->s == NULL || handle->pos == handle->s->length) { ++ if (handle->pos == handle->gb.length) { + char *p; +- handle->s = StrmyISgets(handle->is); +- if (handle->s->length == 0) ++ struct growbuf gbtmp; ++ ++ ISgets_to_growbuf(handle->is, &handle->gb, TRUE); ++ if (handle->gb.length == 0) + return 0; +- cleanup_line(handle->s, PAGER_MODE); + if (handle->encoding == ENC_BASE64) +- Strchop(handle->s); ++ memchop(handle->gb.ptr, &handle->gb.length); + else if (handle->encoding == ENC_UUENCODE) { +- if (!strncmp(handle->s->ptr, "begin", 5)) +- handle->s = StrmyISgets(handle->is); +- Strchop(handle->s); ++ if (handle->gb.length >= 5 && ++ !strncmp(handle->gb.ptr, "begin", 5)) ++ ISgets_to_growbuf(handle->is, &handle->gb, TRUE); ++ memchop(handle->gb.ptr, &handle->gb.length); + } +- p = handle->s->ptr; ++ growbuf_init_without_GC(&gbtmp); ++ p = handle->gb.ptr; + if (handle->encoding == ENC_QUOTE) +- handle->s = decodeQP(&p); ++ decodeQP_to_growbuf(&gbtmp, &p); + else if (handle->encoding == ENC_BASE64) +- handle->s = decodeB(&p); ++ decodeB_to_growbuf(&gbtmp, &p); + else if (handle->encoding == ENC_UUENCODE) +- handle->s = decodeU(&p); ++ decodeU_to_growbuf(&gbtmp, &p); ++ growbuf_clear(&handle->gb); ++ handle->gb = gbtmp; + handle->pos = 0; + } + +- if (len > handle->s->length - handle->pos) +- len = handle->s->length - handle->pos; ++ if (len > handle->gb.length - handle->pos) ++ len = handle->gb.length - handle->pos; + +- bcopy(&handle->s->ptr[handle->pos], buf, len); ++ memcpy(buf, &handle->gb.ptr[handle->pos], len); + handle->pos += len; + return len; + } ++ ++static void ++memchop(char *p, int *len) ++{ ++ char *q; ++ ++ for (q = p + *len; q > p; --q) { ++ if (q[-1] != '\n' && q[-1] != '\r') ++ break; ++ } ++ if (q != p + *len) ++ *q = '\0'; ++ *len = q - p; ++ return; ++} +diff --git a/istream.h b/istream.h +index e710e78..5a04be0 100644 +--- a/istream.h ++++ b/istream.h +@@ -2,13 +2,13 @@ + #ifndef IO_STREAM_H + #define IO_STREAM_H + ++#include "indep.h" + #include <stdio.h> + #ifdef USE_SSL + #include <openssl/bio.h> + #include <openssl/x509.h> + #include <openssl/ssl.h> + #endif +-#include "Str.h" + #include <sys/types.h> + #include <sys/stat.h> + #include <fcntl.h> +@@ -36,7 +36,7 @@ union input_stream; + + struct ens_handle { + union input_stream *is; +- Str s; ++ struct growbuf gb; + int pos; + char encoding; + }; +@@ -119,9 +119,14 @@ extern InputStream newEncodedStream(InputStream is, char encoding); + extern int ISclose(InputStream stream); + extern int ISgetc(InputStream stream); + extern int ISundogetc(InputStream stream); +-extern Str StrISgets(InputStream stream); +-extern Str StrmyISgets(InputStream stream); ++extern Str StrISgets2(InputStream stream, char crnl); ++#define StrISgets(stream) StrISgets2(stream, FALSE) ++#define StrmyISgets(stream) StrISgets2(stream, TRUE) ++void ISgets_to_growbuf(InputStream stream, struct growbuf *gb, char crnl); ++#ifdef unused + extern int ISread(InputStream stream, Str buf, int count); ++#endif ++int ISread_n(InputStream stream, char *dst, int bufsize); + extern int ISfileno(InputStream stream); + extern int ISeos(InputStream stream); + #ifdef USE_SSL +diff --git a/local.c b/local.c +index f5a73a2..959bd66 100644 +--- a/local.c ++++ b/local.c +@@ -359,6 +359,10 @@ localcgi_post(char *uri, char *qstr, FormList *request, char *referer) + int status; + pid_t pid; + char *file = uri, *name = uri, *path_info = NULL, *tmpf = NULL; ++#ifdef HAVE_CHDIR ++ char *cgi_dir; ++#endif ++ char *cgi_basename; + + #ifdef __MINGW32_VERSION + return NULL; +@@ -373,7 +377,14 @@ localcgi_post(char *uri, char *qstr, FormList *request, char *referer) + if (!fw) + return NULL; + } ++ if (qstr) ++ uri = Strnew_m_charp(uri, "?", qstr, NULL)->ptr; ++#ifdef HAVE_CHDIR ++ cgi_dir = mydirname(file); ++#endif ++ cgi_basename = mybasename(file); + pid = open_pipe_rw(&fr, NULL); ++ /* Don't invoke gc after here, or the program might crash in some platforms */ + if (pid < 0) + return NULL; + else if (pid) { +@@ -383,8 +394,6 @@ localcgi_post(char *uri, char *qstr, FormList *request, char *referer) + } + setup_child(TRUE, 2, fw ? fileno(fw) : -1); + +- if (qstr) +- uri = Strnew_m_charp(uri, "?", qstr, NULL)->ptr; + set_cgi_environ(name, file, uri); + if (path_info) + set_environ("PATH_INFO", path_info); +@@ -415,11 +424,11 @@ localcgi_post(char *uri, char *qstr, FormList *request, char *referer) + } + + #ifdef HAVE_CHDIR /* ifndef __EMX__ ? */ +- chdir(mydirname(file)); ++ chdir(cgi_dir); + #endif +- execl(file, mybasename(file), NULL); ++ execl(file, cgi_basename, NULL); + fprintf(stderr, "execl(\"%s\", \"%s\", NULL): %s\n", +- file, mybasename(file), strerror(errno)); ++ file, cgi_basename, strerror(errno)); + exit(1); + return NULL; + #endif +diff --git a/main.c b/main.c +index c49985d..ec77085 100644 +--- a/main.c ++++ b/main.c +@@ -11,6 +11,9 @@ + #include <sys/wait.h> + #endif + #include <time.h> ++#if defined(__CYGWIN__) && defined(USE_BINMODE_STREAM) ++#include <io.h> ++#endif + #include "terms.h" + #include "myctype.h" + #include "regex.h" +@@ -407,6 +410,10 @@ main(int argc, char **argv, char **envp) + wc_ces CodePage; + #endif + #endif ++#if defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) ++ char **getimage_args = NULL; ++#endif /* defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) */ ++ + GC_INIT(); + #if defined(ENABLE_NLS) || (defined(USE_M17N) && defined(HAVE_LANGINFO_CODESET)) + setlocale(LC_ALL, ""); +@@ -428,6 +435,10 @@ main(int argc, char **argv, char **envp) + + CurrentDir = currentdir(); + CurrentPid = (int)getpid(); ++#if defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) ++ if (argv[0] && *argv[0]) ++ MyProgramName = argv[0]; ++#endif /* defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) */ + BookmarkFile = NULL; + config_file = NULL; + +@@ -751,6 +762,15 @@ main(int argc, char **argv, char **envp) + else if (!strcmp("-reqlog",argv[i])) { + w3m_reqlog=rcFile("request.log"); + } ++#if defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) ++ else if (!strcmp("-$$getimage", argv[i])) { ++ ++i; ++ getimage_args = argv + i; ++ i += 4; ++ if (i > argc) ++ usage(); ++ } ++#endif /* defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) */ + else { + usage(); + } +@@ -839,6 +859,30 @@ main(int argc, char **argv, char **envp) + + if (w3m_backend) + backend(); ++#if defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) ++ if (getimage_args) { ++ char *image_url = conv_from_system(getimage_args[0]); ++ char *base_url = conv_from_system(getimage_args[1]); ++ ParsedURL base_pu; ++ ++ parseURL2(base_url, &base_pu, NULL); ++ image_source = getimage_args[2]; ++ newbuf = loadGeneralFile(image_url, &base_pu, NULL, 0, NULL); ++ if (!newbuf || !newbuf->real_type || ++ strncasecmp(newbuf->real_type, "image/", 6)) ++ unlink(getimage_args[2]); ++#if defined(HAVE_SYMLINK) && defined(HAVE_LSTAT) ++ symlink(getimage_args[2], getimage_args[3]); ++#else ++ { ++ FILE *f = fopen(getimage_args[3], "w"); ++ if (f) ++ fclose(f); ++ } ++#endif ++ w3m_exit(0); ++ } ++#endif /* defined(DONT_CALL_GC_AFTER_FORK) && defined(USE_IMAGE) */ + + if (w3m_dump) + mySignal(SIGINT, SIG_IGN); +diff --git a/mimehead.c b/mimehead.c +index 78997e0..d16270c 100644 +--- a/mimehead.c ++++ b/mimehead.c +@@ -64,12 +64,22 @@ ha2d(char x, char y) + Str + decodeB(char **ww) + { ++ struct growbuf gb; ++ ++ growbuf_init(&gb); ++ decodeB_to_growbuf(&gb, ww); ++ return growbuf_to_Str(&gb); ++} ++ ++void ++decodeB_to_growbuf(struct growbuf *gb, char **ww) ++{ + unsigned char c[4]; + char *wp = *ww; + char d[3]; + int i, n_pad; +- Str ap = Strnew_size(strlen(wp)); + ++ growbuf_reserve(gb, strlen(wp) + 1); + n_pad = 0; + while (1) { + for (i = 0; i < 4; i++) { +@@ -93,39 +103,50 @@ decodeB(char **ww) + for (i = 0; i < 4; i++) { + c[i] = c2e(c[i]); + if (c[i] == BAD_BASE64) { +- *ww = wp; +- return ap; ++ goto last; + } + } + d[0] = ((c[0] << 2) | (c[1] >> 4)); + d[1] = ((c[1] << 4) | (c[2] >> 2)); + d[2] = ((c[2] << 6) | c[3]); + for (i = 0; i < 3 - n_pad; i++) { +- Strcat_char(ap, d[i]); ++ GROWBUF_ADD_CHAR(gb, d[i]); + } + if (n_pad || *wp == '\0' || *wp == '?') + break; + } ++last: ++ growbuf_reserve(gb, gb->length + 1); ++ gb->ptr[gb->length] = '\0'; + *ww = wp; +- return ap; ++ return; + } + + Str + decodeU(char **ww) + { ++ struct growbuf gb; ++ ++ growbuf_init(&gb); ++ decodeU_to_growbuf(&gb, ww); ++ return growbuf_to_Str(&gb); ++} ++ ++void ++decodeU_to_growbuf(struct growbuf *gb, char **ww) ++{ + unsigned char c1, c2; + char *w = *ww; + int n, i; +- Str a; + + if (*w <= 0x20 || *w >= 0x60) +- return Strnew_size(0); ++ return; + n = *w - 0x20; +- a = Strnew_size(n); ++ growbuf_reserve(gb, n + 1); + for (w++, i = 2; *w != '\0' && n; n--) { + c1 = (w[0] - 0x20) % 0x40; + c2 = (w[1] - 0x20) % 0x40; +- Strcat_char(a, (c1 << i) | (c2 >> (6 - i))); ++ gb->ptr[gb->length++] = (c1 << i) | (c2 >> (6 - i)); + if (i == 6) { + w += 2; + i = 2; +@@ -135,7 +156,8 @@ decodeU(char **ww) + i += 2; + } + } +- return a; ++ gb->ptr[gb->length] = '\0'; ++ return; + } + + /* RFC2047 (4.2. The "Q" encoding) */ +@@ -165,9 +187,19 @@ decodeQ(char **ww) + Str + decodeQP(char **ww) + { ++ struct growbuf gb; ++ ++ growbuf_init(&gb); ++ decodeQP_to_growbuf(&gb, ww); ++ return growbuf_to_Str(&gb); ++} ++ ++void ++decodeQP_to_growbuf(struct growbuf *gb, char **ww) ++{ + char *w = *ww; +- Str a = Strnew_size(strlen(w)); + ++ growbuf_reserve(gb, strlen(w) + 1); + for (; *w != '\0'; w++) { + if (*w == '=') { + w++; +@@ -180,15 +212,16 @@ decodeQP(char **ww) + else { + if (*w == '\0' || *(w + 1) == '\0') + break; +- Strcat_char(a, ha2d(*w, *(w + 1))); ++ gb->ptr[gb->length++] = ha2d(*w, *(w + 1)); + w++; + } + } + else +- Strcat_char(a, *w); ++ gb->ptr[gb->length++] = *w; + } ++ gb->ptr[gb->length] = '\0'; + *ww = w; +- return a; ++ return; + } + + #ifdef USE_M17N +diff --git a/proto.h b/proto.h +index 7248ee5..0d8beb5 100644 +--- a/proto.h ++++ b/proto.h +@@ -607,9 +607,12 @@ extern char *getAnchorText(Buffer *buf, AnchorList *al, Anchor *a); + extern Buffer *link_list_panel(Buffer *buf); + + extern Str decodeB(char **ww); ++extern void decodeB_to_growbuf(struct growbuf *gb, char **ww); + extern Str decodeQ(char **ww); + extern Str decodeQP(char **ww); ++extern void decodeQP_to_growbuf(struct growbuf *gb, char **ww); + extern Str decodeU(char **ww); ++extern void decodeU_to_growbuf(struct growbuf *gb, char **ww); + #ifdef USE_M17N + extern Str decodeWord(char **ow, wc_ces * charset); + extern Str decodeMIME(Str orgstr, wc_ces * charset); +@@ -811,5 +814,3 @@ extern void dispVer(void); + void srand48(long); + long lrand48(void); + #endif +- +-#include "indep.h" |