aboutsummaryrefslogtreecommitdiffstats
path: root/debian/patches/240_win64gc.patch
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--debian/patches/240_win64gc.patch1235
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"