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