]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - misc.c
Pull out parsing of ^C style strings from the terminal answerback code to
[PuTTY.git] / misc.c
1 /*
2  * Platform-independent routines shared between all PuTTY programs.
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stdarg.h>
8 #include <limits.h>
9 #include <ctype.h>
10 #include <assert.h>
11 #include "putty.h"
12
13 /*
14  * Parse a string block size specification. This is approximately a
15  * subset of the block size specs supported by GNU fileutils:
16  *  "nk" = n kilobytes
17  *  "nM" = n megabytes
18  *  "nG" = n gigabytes
19  * All numbers are decimal, and suffixes refer to powers of two.
20  * Case-insensitive.
21  */
22 unsigned long parse_blocksize(const char *bs)
23 {
24     char *suf;
25     unsigned long r = strtoul(bs, &suf, 10);
26     if (*suf != '\0') {
27         while (*suf && isspace((unsigned char)*suf)) suf++;
28         switch (*suf) {
29           case 'k': case 'K':
30             r *= 1024ul;
31             break;
32           case 'm': case 'M':
33             r *= 1024ul * 1024ul;
34             break;
35           case 'g': case 'G':
36             r *= 1024ul * 1024ul * 1024ul;
37             break;
38           case '\0':
39           default:
40             break;
41         }
42     }
43     return r;
44 }
45
46 /*
47  * Parse a ^C style character specification.
48  * Returns NULL in `next' if we didn't recognise it as a control character,
49  * in which case `c' should be ignored.
50  * The precise current parsing is an oddity inherited from the terminal
51  * answerback-string parsing code. All sequences are two characters,
52  * starting with '^'. The ones that are worth keeping are probably:
53  *   ^?             127
54  *   ^@A-Z[\]^_     0-31
55  *   a-z            1-26
56  *   ~              ^ escape
57  */
58 char ctrlparse(char *s, char **next)
59 {
60     char c = 0;
61     if (*s != '^') {
62         *next = NULL;
63         return c;
64     } else {
65         s++;
66         if (*s == '\0') {
67             *next = NULL;
68             return c;
69         } else if (*s >= 'a' && *s <= 'z') {
70             c = (*s - ('a' - 1));
71         } else if ((*s >= '@' && *s <= '_') || *s == '?' || (*s & 0x80)) {
72             c = ('@' ^ *s);
73         } else if (*s == '~') {
74             c = '^';
75         }
76         s++;
77         *next = s;
78         return c;
79     }
80 }
81
82 /* ----------------------------------------------------------------------
83  * String handling routines.
84  */
85
86 char *dupstr(const char *s)
87 {
88     char *p = NULL;
89     if (s) {
90         int len = strlen(s);
91         p = snewn(len + 1, char);
92         strcpy(p, s);
93     }
94     return p;
95 }
96
97 /* Allocate the concatenation of N strings. Terminate arg list with NULL. */
98 char *dupcat(const char *s1, ...)
99 {
100     int len;
101     char *p, *q, *sn;
102     va_list ap;
103
104     len = strlen(s1);
105     va_start(ap, s1);
106     while (1) {
107         sn = va_arg(ap, char *);
108         if (!sn)
109             break;
110         len += strlen(sn);
111     }
112     va_end(ap);
113
114     p = snewn(len + 1, char);
115     strcpy(p, s1);
116     q = p + strlen(p);
117
118     va_start(ap, s1);
119     while (1) {
120         sn = va_arg(ap, char *);
121         if (!sn)
122             break;
123         strcpy(q, sn);
124         q += strlen(q);
125     }
126     va_end(ap);
127
128     return p;
129 }
130
131 /*
132  * Do an sprintf(), but into a custom-allocated buffer.
133  * 
134  * Currently I'm doing this via vsnprintf. This has worked so far,
135  * but it's not good, because:
136  * 
137  *  - vsnprintf is not available on all platforms. There's an ifdef
138  *    to use `_vsnprintf', which seems to be the local name for it
139  *    on Windows. Other platforms may lack it completely, in which
140  *    case it'll be time to rewrite this function in a totally
141  *    different way.
142  * 
143  *  - technically you can't reuse a va_list like this: it is left
144  *    unspecified whether advancing a va_list pointer modifies its
145  *    value or something it points to, so on some platforms calling
146  *    vsnprintf twice on the same va_list might fail hideously. It
147  *    would be better to use the `va_copy' macro mandated by C99,
148  *    but that too is not yet ubiquitous.
149  * 
150  * The only `properly' portable solution I can think of is to
151  * implement my own format string scanner, which figures out an
152  * upper bound for the length of each formatting directive,
153  * allocates the buffer as it goes along, and calls sprintf() to
154  * actually process each directive. If I ever need to actually do
155  * this, some caveats:
156  * 
157  *  - It's very hard to find a reliable upper bound for
158  *    floating-point values. %f, in particular, when supplied with
159  *    a number near to the upper or lower limit of representable
160  *    numbers, could easily take several hundred characters. It's
161  *    probably feasible to predict this statically using the
162  *    constants in <float.h>, or even to predict it dynamically by
163  *    looking at the exponent of the specific float provided, but
164  *    it won't be fun.
165  * 
166  *  - Don't forget to _check_, after calling sprintf, that it's
167  *    used at most the amount of space we had available.
168  * 
169  *  - Fault any formatting directive we don't fully understand. The
170  *    aim here is to _guarantee_ that we never overflow the buffer,
171  *    because this is a security-critical function. If we see a
172  *    directive we don't know about, we should panic and die rather
173  *    than run any risk.
174  */
175 char *dupprintf(const char *fmt, ...)
176 {
177     char *ret;
178     va_list ap;
179     va_start(ap, fmt);
180     ret = dupvprintf(fmt, ap);
181     va_end(ap);
182     return ret;
183 }
184 char *dupvprintf(const char *fmt, va_list ap)
185 {
186     char *buf;
187     int len, size;
188
189     buf = snewn(512, char);
190     size = 512;
191
192     while (1) {
193 #ifdef _WINDOWS
194 #define vsnprintf _vsnprintf
195 #endif
196         len = vsnprintf(buf, size, fmt, ap);
197         if (len >= 0 && len < size) {
198             /* This is the C99-specified criterion for snprintf to have
199              * been completely successful. */
200             return buf;
201         } else if (len > 0) {
202             /* This is the C99 error condition: the returned length is
203              * the required buffer size not counting the NUL. */
204             size = len + 1;
205         } else {
206             /* This is the pre-C99 glibc error condition: <0 means the
207              * buffer wasn't big enough, so we enlarge it a bit and hope. */
208             size += 512;
209         }
210         buf = sresize(buf, size, char);
211     }
212 }
213
214 /*
215  * Read an entire line of text from a file. Return a buffer
216  * malloced to be as big as necessary (caller must free).
217  */
218 char *fgetline(FILE *fp)
219 {
220     char *ret = snewn(512, char);
221     int size = 512, len = 0;
222     while (fgets(ret + len, size - len, fp)) {
223         len += strlen(ret + len);
224         if (ret[len-1] == '\n')
225             break;                     /* got a newline, we're done */
226         size = len + 512;
227         ret = sresize(ret, size, char);
228     }
229     if (len == 0) {                    /* first fgets returned NULL */
230         sfree(ret);
231         return NULL;
232     }
233     ret[len] = '\0';
234     return ret;
235 }
236
237 /* ----------------------------------------------------------------------
238  * Base64 encoding routine. This is required in public-key writing
239  * but also in HTTP proxy handling, so it's centralised here.
240  */
241
242 void base64_encode_atom(unsigned char *data, int n, char *out)
243 {
244     static const char base64_chars[] =
245         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
246
247     unsigned word;
248
249     word = data[0] << 16;
250     if (n > 1)
251         word |= data[1] << 8;
252     if (n > 2)
253         word |= data[2];
254     out[0] = base64_chars[(word >> 18) & 0x3F];
255     out[1] = base64_chars[(word >> 12) & 0x3F];
256     if (n > 1)
257         out[2] = base64_chars[(word >> 6) & 0x3F];
258     else
259         out[2] = '=';
260     if (n > 2)
261         out[3] = base64_chars[word & 0x3F];
262     else
263         out[3] = '=';
264 }
265
266 /* ----------------------------------------------------------------------
267  * Generic routines to deal with send buffers: a linked list of
268  * smallish blocks, with the operations
269  * 
270  *  - add an arbitrary amount of data to the end of the list
271  *  - remove the first N bytes from the list
272  *  - return a (pointer,length) pair giving some initial data in
273  *    the list, suitable for passing to a send or write system
274  *    call
275  *  - retrieve a larger amount of initial data from the list
276  *  - return the current size of the buffer chain in bytes
277  */
278
279 #define BUFFER_GRANULE  512
280
281 struct bufchain_granule {
282     struct bufchain_granule *next;
283     int buflen, bufpos;
284     char buf[BUFFER_GRANULE];
285 };
286
287 void bufchain_init(bufchain *ch)
288 {
289     ch->head = ch->tail = NULL;
290     ch->buffersize = 0;
291 }
292
293 void bufchain_clear(bufchain *ch)
294 {
295     struct bufchain_granule *b;
296     while (ch->head) {
297         b = ch->head;
298         ch->head = ch->head->next;
299         sfree(b);
300     }
301     ch->tail = NULL;
302     ch->buffersize = 0;
303 }
304
305 int bufchain_size(bufchain *ch)
306 {
307     return ch->buffersize;
308 }
309
310 void bufchain_add(bufchain *ch, const void *data, int len)
311 {
312     const char *buf = (const char *)data;
313
314     if (len == 0) return;
315
316     ch->buffersize += len;
317
318     if (ch->tail && ch->tail->buflen < BUFFER_GRANULE) {
319         int copylen = min(len, BUFFER_GRANULE - ch->tail->buflen);
320         memcpy(ch->tail->buf + ch->tail->buflen, buf, copylen);
321         buf += copylen;
322         len -= copylen;
323         ch->tail->buflen += copylen;
324     }
325     while (len > 0) {
326         int grainlen = min(len, BUFFER_GRANULE);
327         struct bufchain_granule *newbuf;
328         newbuf = snew(struct bufchain_granule);
329         newbuf->bufpos = 0;
330         newbuf->buflen = grainlen;
331         memcpy(newbuf->buf, buf, grainlen);
332         buf += grainlen;
333         len -= grainlen;
334         if (ch->tail)
335             ch->tail->next = newbuf;
336         else
337             ch->head = ch->tail = newbuf;
338         newbuf->next = NULL;
339         ch->tail = newbuf;
340     }
341 }
342
343 void bufchain_consume(bufchain *ch, int len)
344 {
345     struct bufchain_granule *tmp;
346
347     assert(ch->buffersize >= len);
348     while (len > 0) {
349         int remlen = len;
350         assert(ch->head != NULL);
351         if (remlen >= ch->head->buflen - ch->head->bufpos) {
352             remlen = ch->head->buflen - ch->head->bufpos;
353             tmp = ch->head;
354             ch->head = tmp->next;
355             sfree(tmp);
356             if (!ch->head)
357                 ch->tail = NULL;
358         } else
359             ch->head->bufpos += remlen;
360         ch->buffersize -= remlen;
361         len -= remlen;
362     }
363 }
364
365 void bufchain_prefix(bufchain *ch, void **data, int *len)
366 {
367     *len = ch->head->buflen - ch->head->bufpos;
368     *data = ch->head->buf + ch->head->bufpos;
369 }
370
371 void bufchain_fetch(bufchain *ch, void *data, int len)
372 {
373     struct bufchain_granule *tmp;
374     char *data_c = (char *)data;
375
376     tmp = ch->head;
377
378     assert(ch->buffersize >= len);
379     while (len > 0) {
380         int remlen = len;
381
382         assert(tmp != NULL);
383         if (remlen >= tmp->buflen - tmp->bufpos)
384             remlen = tmp->buflen - tmp->bufpos;
385         memcpy(data_c, tmp->buf + tmp->bufpos, remlen);
386
387         tmp = tmp->next;
388         len -= remlen;
389         data_c += remlen;
390     }
391 }
392
393 /* ----------------------------------------------------------------------
394  * My own versions of malloc, realloc and free. Because I want
395  * malloc and realloc to bomb out and exit the program if they run
396  * out of memory, realloc to reliably call malloc if passed a NULL
397  * pointer, and free to reliably do nothing if passed a NULL
398  * pointer. We can also put trace printouts in, if we need to; and
399  * we can also replace the allocator with an ElectricFence-like
400  * one.
401  */
402
403 #ifdef MINEFIELD
404 void *minefield_c_malloc(size_t size);
405 void minefield_c_free(void *p);
406 void *minefield_c_realloc(void *p, size_t size);
407 #endif
408
409 #ifdef MALLOC_LOG
410 static FILE *fp = NULL;
411
412 static char *mlog_file = NULL;
413 static int mlog_line = 0;
414
415 void mlog(char *file, int line)
416 {
417     mlog_file = file;
418     mlog_line = line;
419     if (!fp) {
420         fp = fopen("putty_mem.log", "w");
421         setvbuf(fp, NULL, _IONBF, BUFSIZ);
422     }
423     if (fp)
424         fprintf(fp, "%s:%d: ", file, line);
425 }
426 #endif
427
428 void *safemalloc(size_t n, size_t size)
429 {
430     void *p;
431
432     if (n > INT_MAX / size) {
433         p = NULL;
434     } else {
435         size *= n;
436 #ifdef MINEFIELD
437         p = minefield_c_malloc(size);
438 #else
439         p = malloc(size);
440 #endif
441     }
442
443     if (!p) {
444         char str[200];
445 #ifdef MALLOC_LOG
446         sprintf(str, "Out of memory! (%s:%d, size=%d)",
447                 mlog_file, mlog_line, size);
448         fprintf(fp, "*** %s\n", str);
449         fclose(fp);
450 #else
451         strcpy(str, "Out of memory!");
452 #endif
453         modalfatalbox(str);
454     }
455 #ifdef MALLOC_LOG
456     if (fp)
457         fprintf(fp, "malloc(%d) returns %p\n", size, p);
458 #endif
459     return p;
460 }
461
462 void *saferealloc(void *ptr, size_t n, size_t size)
463 {
464     void *p;
465
466     if (n > INT_MAX / size) {
467         p = NULL;
468     } else {
469         size *= n;
470         if (!ptr) {
471 #ifdef MINEFIELD
472             p = minefield_c_malloc(size);
473 #else
474             p = malloc(size);
475 #endif
476         } else {
477 #ifdef MINEFIELD
478             p = minefield_c_realloc(ptr, size);
479 #else
480             p = realloc(ptr, size);
481 #endif
482         }
483     }
484
485     if (!p) {
486         char str[200];
487 #ifdef MALLOC_LOG
488         sprintf(str, "Out of memory! (%s:%d, size=%d)",
489                 mlog_file, mlog_line, size);
490         fprintf(fp, "*** %s\n", str);
491         fclose(fp);
492 #else
493         strcpy(str, "Out of memory!");
494 #endif
495         modalfatalbox(str);
496     }
497 #ifdef MALLOC_LOG
498     if (fp)
499         fprintf(fp, "realloc(%p,%d) returns %p\n", ptr, size, p);
500 #endif
501     return p;
502 }
503
504 void safefree(void *ptr)
505 {
506     if (ptr) {
507 #ifdef MALLOC_LOG
508         if (fp)
509             fprintf(fp, "free(%p)\n", ptr);
510 #endif
511 #ifdef MINEFIELD
512         minefield_c_free(ptr);
513 #else
514         free(ptr);
515 #endif
516     }
517 #ifdef MALLOC_LOG
518     else if (fp)
519         fprintf(fp, "freeing null pointer - no action taken\n");
520 #endif
521 }
522
523 /* ----------------------------------------------------------------------
524  * Debugging routines.
525  */
526
527 #ifdef DEBUG
528 extern void dputs(char *);             /* defined in per-platform *misc.c */
529
530 void debug_printf(char *fmt, ...)
531 {
532     char *buf;
533     va_list ap;
534
535     va_start(ap, fmt);
536     buf = dupvprintf(fmt, ap);
537     dputs(buf);
538     sfree(buf);
539     va_end(ap);
540 }
541
542
543 void debug_memdump(void *buf, int len, int L)
544 {
545     int i;
546     unsigned char *p = buf;
547     char foo[17];
548     if (L) {
549         int delta;
550         debug_printf("\t%d (0x%x) bytes:\n", len, len);
551         delta = 15 & (int) p;
552         p -= delta;
553         len += delta;
554     }
555     for (; 0 < len; p += 16, len -= 16) {
556         dputs("  ");
557         if (L)
558             debug_printf("%p: ", p);
559         strcpy(foo, "................");        /* sixteen dots */
560         for (i = 0; i < 16 && i < len; ++i) {
561             if (&p[i] < (unsigned char *) buf) {
562                 dputs("   ");          /* 3 spaces */
563                 foo[i] = ' ';
564             } else {
565                 debug_printf("%c%02.2x",
566                         &p[i] != (unsigned char *) buf
567                         && i % 4 ? '.' : ' ', p[i]
568                     );
569                 if (p[i] >= ' ' && p[i] <= '~')
570                     foo[i] = (char) p[i];
571             }
572         }
573         foo[i] = '\0';
574         debug_printf("%*s%s\n", (16 - i) * 3 + 2, "", foo);
575     }
576 }
577
578 #endif                          /* def DEBUG */