2 * Platform-independent routines shared between all PuTTY programs.
13 /* ----------------------------------------------------------------------
14 * String handling routines.
17 char *dupstr(const char *s)
22 p = snewn(len + 1, char);
28 /* Allocate the concatenation of N strings. Terminate arg list with NULL. */
29 char *dupcat(const char *s1, ...)
38 sn = va_arg(ap, char *);
45 p = snewn(len + 1, char);
51 sn = va_arg(ap, char *);
63 * Do an sprintf(), but into a custom-allocated buffer.
65 * Currently I'm doing this via vsnprintf. This has worked so far,
66 * but it's not good, because:
68 * - vsnprintf is not available on all platforms. There's an ifdef
69 * to use `_vsnprintf', which seems to be the local name for it
70 * on Windows. Other platforms may lack it completely, in which
71 * case it'll be time to rewrite this function in a totally
74 * - technically you can't reuse a va_list like this: it is left
75 * unspecified whether advancing a va_list pointer modifies its
76 * value or something it points to, so on some platforms calling
77 * vsnprintf twice on the same va_list might fail hideously. It
78 * would be better to use the `va_copy' macro mandated by C99,
79 * but that too is not yet ubiquitous.
81 * The only `properly' portable solution I can think of is to
82 * implement my own format string scanner, which figures out an
83 * upper bound for the length of each formatting directive,
84 * allocates the buffer as it goes along, and calls sprintf() to
85 * actually process each directive. If I ever need to actually do
88 * - It's very hard to find a reliable upper bound for
89 * floating-point values. %f, in particular, when supplied with
90 * a number near to the upper or lower limit of representable
91 * numbers, could easily take several hundred characters. It's
92 * probably feasible to predict this statically using the
93 * constants in <float.h>, or even to predict it dynamically by
94 * looking at the exponent of the specific float provided, but
97 * - Don't forget to _check_, after calling sprintf, that it's
98 * used at most the amount of space we had available.
100 * - Fault any formatting directive we don't fully understand. The
101 * aim here is to _guarantee_ that we never overflow the buffer,
102 * because this is a security-critical function. If we see a
103 * directive we don't know about, we should panic and die rather
106 char *dupprintf(const char *fmt, ...)
111 ret = dupvprintf(fmt, ap);
115 char *dupvprintf(const char *fmt, va_list ap)
120 buf = snewn(512, char);
125 #define vsnprintf _vsnprintf
127 len = vsnprintf(buf, size, fmt, ap);
128 if (len >= 0 && len < size) {
129 /* This is the C99-specified criterion for snprintf to have
130 * been completely successful. */
132 } else if (len > 0) {
133 /* This is the C99 error condition: the returned length is
134 * the required buffer size not counting the NUL. */
137 /* This is the pre-C99 glibc error condition: <0 means the
138 * buffer wasn't big enough, so we enlarge it a bit and hope. */
141 buf = sresize(buf, size, char);
145 /* ----------------------------------------------------------------------
146 * Base64 encoding routine. This is required in public-key writing
147 * but also in HTTP proxy handling, so it's centralised here.
150 void base64_encode_atom(unsigned char *data, int n, char *out)
152 static const char base64_chars[] =
153 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
157 word = data[0] << 16;
159 word |= data[1] << 8;
162 out[0] = base64_chars[(word >> 18) & 0x3F];
163 out[1] = base64_chars[(word >> 12) & 0x3F];
165 out[2] = base64_chars[(word >> 6) & 0x3F];
169 out[3] = base64_chars[word & 0x3F];
174 /* ----------------------------------------------------------------------
175 * Generic routines to deal with send buffers: a linked list of
176 * smallish blocks, with the operations
178 * - add an arbitrary amount of data to the end of the list
179 * - remove the first N bytes from the list
180 * - return a (pointer,length) pair giving some initial data in
181 * the list, suitable for passing to a send or write system
183 * - retrieve a larger amount of initial data from the list
184 * - return the current size of the buffer chain in bytes
187 #define BUFFER_GRANULE 512
189 struct bufchain_granule {
190 struct bufchain_granule *next;
192 char buf[BUFFER_GRANULE];
195 void bufchain_init(bufchain *ch)
197 ch->head = ch->tail = NULL;
201 void bufchain_clear(bufchain *ch)
203 struct bufchain_granule *b;
206 ch->head = ch->head->next;
213 int bufchain_size(bufchain *ch)
215 return ch->buffersize;
218 void bufchain_add(bufchain *ch, const void *data, int len)
220 const char *buf = (const char *)data;
222 if (len == 0) return;
224 ch->buffersize += len;
226 if (ch->tail && ch->tail->buflen < BUFFER_GRANULE) {
227 int copylen = min(len, BUFFER_GRANULE - ch->tail->buflen);
228 memcpy(ch->tail->buf + ch->tail->buflen, buf, copylen);
231 ch->tail->buflen += copylen;
234 int grainlen = min(len, BUFFER_GRANULE);
235 struct bufchain_granule *newbuf;
236 newbuf = snew(struct bufchain_granule);
238 newbuf->buflen = grainlen;
239 memcpy(newbuf->buf, buf, grainlen);
243 ch->tail->next = newbuf;
245 ch->head = ch->tail = newbuf;
251 void bufchain_consume(bufchain *ch, int len)
253 struct bufchain_granule *tmp;
255 assert(ch->buffersize >= len);
258 assert(ch->head != NULL);
259 if (remlen >= ch->head->buflen - ch->head->bufpos) {
260 remlen = ch->head->buflen - ch->head->bufpos;
262 ch->head = tmp->next;
267 ch->head->bufpos += remlen;
268 ch->buffersize -= remlen;
273 void bufchain_prefix(bufchain *ch, void **data, int *len)
275 *len = ch->head->buflen - ch->head->bufpos;
276 *data = ch->head->buf + ch->head->bufpos;
279 void bufchain_fetch(bufchain *ch, void *data, int len)
281 struct bufchain_granule *tmp;
282 char *data_c = (char *)data;
286 assert(ch->buffersize >= len);
291 if (remlen >= tmp->buflen - tmp->bufpos)
292 remlen = tmp->buflen - tmp->bufpos;
293 memcpy(data_c, tmp->buf + tmp->bufpos, remlen);
301 /* ----------------------------------------------------------------------
302 * My own versions of malloc, realloc and free. Because I want
303 * malloc and realloc to bomb out and exit the program if they run
304 * out of memory, realloc to reliably call malloc if passed a NULL
305 * pointer, and free to reliably do nothing if passed a NULL
306 * pointer. We can also put trace printouts in, if we need to; and
307 * we can also replace the allocator with an ElectricFence-like
312 void *minefield_c_malloc(size_t size);
313 void minefield_c_free(void *p);
314 void *minefield_c_realloc(void *p, size_t size);
318 static FILE *fp = NULL;
320 static char *mlog_file = NULL;
321 static int mlog_line = 0;
323 void mlog(char *file, int line)
328 fp = fopen("putty_mem.log", "w");
329 setvbuf(fp, NULL, _IONBF, BUFSIZ);
332 fprintf(fp, "%s:%d: ", file, line);
336 void *safemalloc(size_t n, size_t size)
340 if (n > INT_MAX / size) {
345 p = minefield_c_malloc(size);
354 sprintf(str, "Out of memory! (%s:%d, size=%d)",
355 mlog_file, mlog_line, size);
356 fprintf(fp, "*** %s\n", str);
359 strcpy(str, "Out of memory!");
365 fprintf(fp, "malloc(%d) returns %p\n", size, p);
370 void *saferealloc(void *ptr, size_t n, size_t size)
374 if (n > INT_MAX / size) {
380 p = minefield_c_malloc(size);
386 p = minefield_c_realloc(ptr, size);
388 p = realloc(ptr, size);
396 sprintf(str, "Out of memory! (%s:%d, size=%d)",
397 mlog_file, mlog_line, size);
398 fprintf(fp, "*** %s\n", str);
401 strcpy(str, "Out of memory!");
407 fprintf(fp, "realloc(%p,%d) returns %p\n", ptr, size, p);
412 void safefree(void *ptr)
417 fprintf(fp, "free(%p)\n", ptr);
420 minefield_c_free(ptr);
427 fprintf(fp, "freeing null pointer - no action taken\n");
431 /* ----------------------------------------------------------------------
432 * Debugging routines.
436 extern void dputs(char *); /* defined in per-platform *misc.c */
438 void debug_printf(char *fmt, ...)
444 buf = dupvprintf(fmt, ap);
451 void debug_memdump(void *buf, int len, int L)
454 unsigned char *p = buf;
458 debug_printf("\t%d (0x%x) bytes:\n", len, len);
459 delta = 15 & (int) p;
463 for (; 0 < len; p += 16, len -= 16) {
466 debug_printf("%p: ", p);
467 strcpy(foo, "................"); /* sixteen dots */
468 for (i = 0; i < 16 && i < len; ++i) {
469 if (&p[i] < (unsigned char *) buf) {
470 dputs(" "); /* 3 spaces */
473 debug_printf("%c%02.2x",
474 &p[i] != (unsigned char *) buf
475 && i % 4 ? '.' : ' ', p[i]
477 if (p[i] >= ' ' && p[i] <= '~')
478 foo[i] = (char) p[i];
482 debug_printf("%*s%s\n", (16 - i) * 3 + 2, "", foo);
486 #endif /* def DEBUG */