X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/93b581bd031b2270deb7f45440e61a1044fe94da..86916870d36cb70e7ef0ea760e75a6ae8b2d83a5:/misc.c diff --git a/misc.c b/misc.c index ee1abf7b..e4c6d4ac 100644 --- a/misc.c +++ b/misc.c @@ -1,6 +1,7 @@ -#include #include #include +#include +#include #include #include "putty.h" @@ -8,7 +9,7 @@ * String handling routines. */ -char *dupstr(char *s) +char *dupstr(const char *s) { int len = strlen(s); char *p = smalloc(len + 1); @@ -17,7 +18,7 @@ char *dupstr(char *s) } /* Allocate the concatenation of N strings. Terminate arg list with NULL. */ -char *dupcat(char *s1, ...) +char *dupcat(const char *s1, ...) { int len; char *p, *q, *sn; @@ -50,6 +51,85 @@ char *dupcat(char *s1, ...) return p; } +/* + * Do an sprintf(), but into a custom-allocated buffer. + * + * Irritatingly, we don't seem to be able to do this portably using + * vsnprintf(), because there appear to be issues with re-using the + * same va_list for two calls, and the excellent C99 va_copy is not + * yet widespread. Bah. Instead I'm going to do a horrid, horrid + * hack, in which I trawl the format string myself, work out the + * maximum length of each format component, and resize the buffer + * before printing it. + */ +char *dupprintf(const char *fmt, ...) +{ + char *ret; + va_list ap; + va_start(ap, fmt); + ret = dupvprintf(fmt, ap); + va_end(ap); + return ret; +} +char *dupvprintf(const char *fmt, va_list ap) +{ + char *buf; + int len, size; + + buf = smalloc(512); + size = 512; + + while (1) { +#ifdef _WINDOWS +#define vsnprintf _vsnprintf +#endif + len = vsnprintf(buf, size, fmt, ap); + if (len >= 0 && len < size) { + /* This is the C99-specified criterion for snprintf to have + * been completely successful. */ + return buf; + } else if (len > 0) { + /* This is the C99 error condition: the returned length is + * the required buffer size not counting the NUL. */ + size = len + 1; + } else { + /* This is the pre-C99 glibc error condition: <0 means the + * buffer wasn't big enough, so we enlarge it a bit and hope. */ + size += 512; + } + buf = srealloc(buf, size); + } +} + +/* ---------------------------------------------------------------------- + * Base64 encoding routine. This is required in public-key writing + * but also in HTTP proxy handling, so it's centralised here. + */ + +void base64_encode_atom(unsigned char *data, int n, char *out) +{ + static const char base64_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + unsigned word; + + word = data[0] << 16; + if (n > 1) + word |= data[1] << 8; + if (n > 2) + word |= data[2]; + out[0] = base64_chars[(word >> 18) & 0x3F]; + out[1] = base64_chars[(word >> 12) & 0x3F]; + if (n > 1) + out[2] = base64_chars[(word >> 6) & 0x3F]; + else + out[2] = '='; + if (n > 2) + out[3] = base64_chars[word & 0x3F]; + else + out[3] = '='; +} + /* ---------------------------------------------------------------------- * Generic routines to deal with send buffers: a linked list of * smallish blocks, with the operations @@ -59,6 +139,7 @@ char *dupcat(char *s1, ...) * - return a (pointer,length) pair giving some initial data in * the list, suitable for passing to a send or write system * call + * - retrieve a larger amount of initial data from the list * - return the current size of the buffer chain in bytes */ @@ -93,9 +174,9 @@ int bufchain_size(bufchain *ch) return ch->buffersize; } -void bufchain_add(bufchain *ch, void *data, int len) +void bufchain_add(bufchain *ch, const void *data, int len) { - char *buf = (char *)data; + const char *buf = (const char *)data; ch->buffersize += len; @@ -126,16 +207,23 @@ void bufchain_add(bufchain *ch, void *data, int len) void bufchain_consume(bufchain *ch, int len) { + struct bufchain_granule *tmp; + assert(ch->buffersize >= len); - assert(ch->head != NULL && ch->head->bufpos + len <= ch->head->buflen); - ch->head->bufpos += len; - ch->buffersize -= len; - if (ch->head->bufpos >= ch->head->buflen) { - struct bufchain_granule *tmp = ch->head; - ch->head = tmp->next; - sfree(tmp); - if (!ch->head) - ch->tail = NULL; + while (len > 0) { + int remlen = len; + assert(ch->head != NULL); + if (remlen >= ch->head->buflen - ch->head->bufpos) { + remlen = ch->head->buflen - ch->head->bufpos; + tmp = ch->head; + ch->head = tmp->next; + sfree(tmp); + if (!ch->head) + ch->tail = NULL; + } else + ch->head->bufpos += remlen; + ch->buffersize -= remlen; + len -= remlen; } } @@ -145,6 +233,28 @@ void bufchain_prefix(bufchain *ch, void **data, int *len) *data = ch->head->buf + ch->head->bufpos; } +void bufchain_fetch(bufchain *ch, void *data, int len) +{ + struct bufchain_granule *tmp; + char *data_c = (char *)data; + + tmp = ch->head; + + assert(ch->buffersize >= len); + while (len > 0) { + int remlen = len; + + assert(tmp != NULL); + if (remlen >= tmp->buflen - tmp->bufpos) + remlen = tmp->buflen - tmp->bufpos; + memcpy(data_c, tmp->buf + tmp->bufpos, remlen); + + tmp = tmp->next; + len -= remlen; + data_c += remlen; + } +} + /* ---------------------------------------------------------------------- * My own versions of malloc, realloc and free. Because I want * malloc and realloc to bomb out and exit the program if they run @@ -294,7 +404,7 @@ static void *minefield_alloc(int size) /* * Update the admin region. */ - for (i = start + 2; i < start + npages - 1; i++) + for (i = start + 2; i < start + npages + 1; i++) minefield_admin[i] = 0xFFFE; /* used but no region starts here */ minefield_admin[start + 1] = region_start % PAGESIZE; @@ -413,9 +523,7 @@ void *safemalloc(size_t size) #else strcpy(str, "Out of memory!"); #endif - MessageBox(NULL, str, "PuTTY Fatal Error", - MB_SYSTEMMODAL | MB_ICONERROR | MB_OK); - cleanup_exit(1); + modalfatalbox(str); } #ifdef MALLOC_LOG if (fp) @@ -450,9 +558,7 @@ void *saferealloc(void *ptr, size_t size) #else strcpy(str, "Out of memory!"); #endif - MessageBox(NULL, str, "PuTTY Fatal Error", - MB_SYSTEMMODAL | MB_ICONERROR | MB_OK); - cleanup_exit(1); + modalfatalbox(str); } #ifdef MALLOC_LOG if (fp) @@ -486,6 +592,7 @@ void safefree(void *ptr) #ifdef DEBUG static FILE *debug_fp = NULL; +static HANDLE debug_hdl = INVALID_HANDLE_VALUE; static int debug_got_console = 0; static void dputs(char *buf) @@ -493,15 +600,18 @@ static void dputs(char *buf) DWORD dw; if (!debug_got_console) { - AllocConsole(); - debug_got_console = 1; + if (AllocConsole()) { + debug_got_console = 1; + debug_hdl = GetStdHandle(STD_OUTPUT_HANDLE); + } } if (!debug_fp) { debug_fp = fopen("debug.log", "w"); } - WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, strlen(buf), &dw, - NULL); + if (debug_hdl != INVALID_HANDLE_VALUE) { + WriteFile(debug_hdl, buf, strlen(buf), &dw, NULL); + } fputs(buf, debug_fp); fflush(debug_fp); } @@ -509,12 +619,13 @@ static void dputs(char *buf) void dprintf(char *fmt, ...) { - char buf[2048]; + char *buf; va_list ap; va_start(ap, fmt); - vsprintf(buf, fmt, ap); + buf = dupvprintf(fmt, ap); dputs(buf); + sfree(buf); va_end(ap); }