-#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
#include <assert.h>
#include "putty.h"
+/* ----------------------------------------------------------------------
+ * String handling routines.
+ */
+
+char *dupstr(const char *s)
+{
+ int len = strlen(s);
+ char *p = smalloc(len + 1);
+ strcpy(p, s);
+ return p;
+}
+
+/* Allocate the concatenation of N strings. Terminate arg list with NULL. */
+char *dupcat(const char *s1, ...)
+{
+ int len;
+ char *p, *q, *sn;
+ va_list ap;
+
+ len = strlen(s1);
+ va_start(ap, s1);
+ while (1) {
+ sn = va_arg(ap, char *);
+ if (!sn)
+ break;
+ len += strlen(sn);
+ }
+ va_end(ap);
+
+ p = smalloc(len + 1);
+ strcpy(p, s1);
+ q = p + strlen(p);
+
+ va_start(ap, s1);
+ while (1) {
+ sn = va_arg(ap, char *);
+ if (!sn)
+ break;
+ strcpy(q, sn);
+ q += strlen(q);
+ }
+ va_end(ap);
+
+ 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
*
* - 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
*/
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;
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;
}
}
*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
* out of memory, realloc to reliably call malloc if passed a NULL
/*
* 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;
#ifdef MALLOC_LOG
static FILE *fp = NULL;
+static char *mlog_file = NULL;
+static int mlog_line = 0;
+
void mlog(char *file, int line)
{
+ mlog_file = file;
+ mlog_line = line;
if (!fp) {
fp = fopen("putty_mem.log", "w");
setvbuf(fp, NULL, _IONBF, BUFSIZ);
p = malloc(size);
#endif
if (!p) {
- MessageBox(NULL, "Out of memory!", "PuTTY Fatal Error",
- MB_SYSTEMMODAL | MB_ICONERROR | MB_OK);
- exit(1);
+ char str[200];
+#ifdef MALLOC_LOG
+ sprintf(str, "Out of memory! (%s:%d, size=%d)",
+ mlog_file, mlog_line, size);
+ fprintf(fp, "*** %s\n", str);
+ fclose(fp);
+#else
+ strcpy(str, "Out of memory!");
+#endif
+ modalfatalbox(str);
}
#ifdef MALLOC_LOG
if (fp)
#endif
}
if (!p) {
- MessageBox(NULL, "Out of memory!", "PuTTY Fatal Error",
- MB_SYSTEMMODAL | MB_ICONERROR | MB_OK);
- exit(1);
+ char str[200];
+#ifdef MALLOC_LOG
+ sprintf(str, "Out of memory! (%s:%d, size=%d)",
+ mlog_file, mlog_line, size);
+ fprintf(fp, "*** %s\n", str);
+ fclose(fp);
+#else
+ strcpy(str, "Out of memory!");
+#endif
+ modalfatalbox(str);
}
#ifdef MALLOC_LOG
if (fp)
#endif
}
+/* ----------------------------------------------------------------------
+ * Debugging routines.
+ */
+
#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)
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);
}
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);
}