X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/46cfeac8e5e6263f64f03028b98e27c0b09575f9..208a0f09f8b18915b46d6ad39fc7c2c8f62fb930:/misc.c diff --git a/misc.c b/misc.c index fea96a97..636ca9f3 100644 --- a/misc.c +++ b/misc.c @@ -24,7 +24,7 @@ unsigned long parse_blocksize(const char *bs) char *suf; unsigned long r = strtoul(bs, &suf, 10); if (*suf != '\0') { - while (isspace(*suf)) suf++; + while (*suf && isspace((unsigned char)*suf)) suf++; switch (*suf) { case 'k': case 'K': r *= 1024ul; @@ -43,6 +43,114 @@ unsigned long parse_blocksize(const char *bs) return r; } +/* + * Parse a ^C style character specification. + * Returns NULL in `next' if we didn't recognise it as a control character, + * in which case `c' should be ignored. + * The precise current parsing is an oddity inherited from the terminal + * answerback-string parsing code. All sequences start with ^; all except + * ^<123> are two characters. The ones that are worth keeping are probably: + * ^? 127 + * ^@A-Z[\]^_ 0-31 + * a-z 1-26 + * specified by number (decimal, 0octal, 0xHEX) + * ~ ^ escape + */ +char ctrlparse(char *s, char **next) +{ + char c = 0; + if (*s != '^') { + *next = NULL; + } else { + s++; + if (*s == '\0') { + *next = NULL; + } else if (*s == '<') { + s++; + c = (char)strtol(s, next, 0); + if ((*next == s) || (**next != '>')) { + c = 0; + *next = NULL; + } else + (*next)++; + } else if (*s >= 'a' && *s <= 'z') { + c = (*s - ('a' - 1)); + *next = s+1; + } else if ((*s >= '@' && *s <= '_') || *s == '?' || (*s & 0x80)) { + c = ('@' ^ *s); + *next = s+1; + } else if (*s == '~') { + c = '^'; + *next = s+1; + } + } + return c; +} + +prompts_t *new_prompts(void *frontend) +{ + prompts_t *p = snew(prompts_t); + p->prompts = NULL; + p->n_prompts = 0; + p->frontend = frontend; + p->data = NULL; + p->to_server = TRUE; /* to be on the safe side */ + p->name = p->instruction = NULL; + p->name_reqd = p->instr_reqd = FALSE; + return p; +} +void add_prompt(prompts_t *p, char *promptstr, int echo) +{ + prompt_t *pr = snew(prompt_t); + pr->prompt = promptstr; + pr->echo = echo; + pr->result = NULL; + pr->resultsize = 0; + p->n_prompts++; + p->prompts = sresize(p->prompts, p->n_prompts, prompt_t *); + p->prompts[p->n_prompts-1] = pr; +} +void prompt_ensure_result_size(prompt_t *pr, int newlen) +{ + if ((int)pr->resultsize < newlen) { + char *newbuf; + newlen = newlen * 5 / 4 + 512; /* avoid too many small allocs */ + + /* + * We don't use sresize / realloc here, because we will be + * storing sensitive stuff like passwords in here, and we want + * to make sure that the data doesn't get copied around in + * memory without the old copy being destroyed. + */ + newbuf = snewn(newlen, char); + memcpy(newbuf, pr->result, pr->resultsize); + memset(pr->result, '\0', pr->resultsize); + sfree(pr->result); + pr->result = newbuf; + pr->resultsize = newlen; + } +} +void prompt_set_result(prompt_t *pr, const char *newstr) +{ + prompt_ensure_result_size(pr, strlen(newstr) + 1); + strcpy(pr->result, newstr); +} +void free_prompts(prompts_t *p) +{ + size_t i; + for (i=0; i < p->n_prompts; i++) { + prompt_t *pr = p->prompts[i]; + memset(pr->result, 0, pr->resultsize); /* burn the evidence */ + sfree(pr->result); + sfree(pr->prompt); + sfree(pr); + } + sfree(p->prompts); + sfree(p->name); + sfree(p->instruction); + sfree(p); +} + /* ---------------------------------------------------------------------- * String handling routines. */ @@ -92,24 +200,23 @@ char *dupcat(const char *s1, ...) return p; } +void burnstr(char *string) /* sfree(str), only clear it first */ +{ + if (string) { + memset(string, 0, strlen(string)); + sfree(string); + } +} + /* * Do an sprintf(), but into a custom-allocated buffer. * * Currently I'm doing this via vsnprintf. This has worked so far, - * but it's not good, because: - * - * - vsnprintf is not available on all platforms. There's an ifdef - * to use `_vsnprintf', which seems to be the local name for it - * on Windows. Other platforms may lack it completely, in which - * case it'll be time to rewrite this function in a totally - * different way. - * - * - technically you can't reuse a va_list like this: it is left - * unspecified whether advancing a va_list pointer modifies its - * value or something it points to, so on some platforms calling - * vsnprintf twice on the same va_list might fail hideously. It - * would be better to use the `va_copy' macro mandated by C99, - * but that too is not yet ubiquitous. + * but it's not good, because vsnprintf is not available on all + * platforms. There's an ifdef to use `_vsnprintf', which seems + * to be the local name for it on Windows. Other platforms may + * lack it completely, in which case it'll be time to rewrite + * this function in a totally different way. * * The only `properly' portable solution I can think of is to * implement my own format string scanner, which figures out an @@ -157,7 +264,24 @@ char *dupvprintf(const char *fmt, va_list ap) #ifdef _WINDOWS #define vsnprintf _vsnprintf #endif +#ifdef va_copy + /* Use the `va_copy' macro mandated by C99, if present. + * XXX some environments may have this as __va_copy() */ + va_list aq; + va_copy(aq, ap); + len = vsnprintf(buf, size, fmt, aq); + va_end(aq); +#else + /* Ugh. No va_copy macro, so do something nasty. + * Technically, you can't reuse a va_list like this: it is left + * unspecified whether advancing a va_list pointer modifies its + * value or something it points to, so on some platforms calling + * vsnprintf twice on the same va_list might fail hideously + * (indeed, it has been observed to). + * XXX the autoconf manual suggests that using memcpy() will give + * "maximum portability". */ len = vsnprintf(buf, size, fmt, ap); +#endif if (len >= 0 && len < size) { /* This is the C99-specified criterion for snprintf to have * been completely successful. */ @@ -397,6 +521,7 @@ void *safemalloc(size_t n, size_t size) p = NULL; } else { size *= n; + if (size == 0) size = 1; #ifdef MINEFIELD p = minefield_c_malloc(size); #else @@ -512,7 +637,7 @@ void debug_memdump(void *buf, int len, int L) if (L) { int delta; debug_printf("\t%d (0x%x) bytes:\n", len, len); - delta = 15 & (int) p; + delta = 15 & (unsigned long int) p; p -= delta; len += delta; } @@ -540,3 +665,23 @@ void debug_memdump(void *buf, int len, int L) } #endif /* def DEBUG */ + +/* + * Determine whether or not a Conf represents a session which can + * sensibly be launched right now. + */ +int conf_launchable(Conf *conf) +{ + if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL) + return conf_get_str(conf, CONF_serline)[0] != 0; + else + return conf_get_str(conf, CONF_host)[0] != 0; +} + +char const *conf_dest(Conf *conf) +{ + if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL) + return conf_get_str(conf, CONF_serline); + else + return conf_get_str(conf, CONF_host); +}