77,11 → 77,13 |
*/ |
size_t cli_redup(char **s1, const char *s2) |
{ |
size_t len = strlen(s2) + 1; |
size_t len; |
|
if (! len) |
if (s2 == NULL) |
return -1; |
|
len = strlen(s2) + 1; |
|
*s1 = realloc(*s1, len); |
|
if (*s1 == NULL) { |
89,106 → 91,14 |
return -1; |
} |
|
memset(*s1, 0, sizeof(*s1)); |
*s1[len] = '\0'; |
|
memcpy(*s1, s2, len); |
cli_errno = CL_EOK; |
|
return len; |
} |
|
/* An asprintf() for formatting paths, similar to asprintf() but ensures |
* the returned allocated string is <= PATH_MAX. On failure, an attempt |
* is made to return the original string (if not null) unmodified. |
* |
* Returns: Length of the new string on success, 0 if the string was handed |
* back unmodified, -1 on failure. On failure, cli_errno is set. |
* |
* We do not use POSIX_PATH_MAX, as it is typically much smaller than the |
* PATH_MAX defined by the kernel. |
* |
* Use this like: |
* if (1 > cli_psprintf(&char, "%s/%s", foo, bar)) { |
* cli_error(cli_errno, "Failed to format path"); |
* stop_what_your_doing_as_your_out_of_memory(); |
* } |
*/ |
|
int cli_psprintf(char **s1, const char *fmt, ...) |
{ |
va_list ap; |
size_t needed, base = PATH_MAX + 1; |
int skipped = 0; |
char *orig = NULL; |
char *tmp = (char *) malloc(base); |
|
/* Don't even touch s1, not enough memory */ |
if (NULL == tmp) { |
cli_errno = CL_ENOMEM; |
return -1; |
} |
|
/* If re-allocating s1, save a copy in case we fail */ |
if (NULL != *s1) |
orig = cli_strdup(*s1); |
|
/* Print the string to tmp so we can determine the size that |
* we actually need */ |
memset(tmp, 0, sizeof(tmp)); |
va_start(ap, fmt); |
/* vsnprintf will return the # of bytes not written */ |
skipped = vsnprintf(tmp, base, fmt, ap); |
va_end(ap); |
|
/* realloc/alloc s1 to be just the size that we need */ |
needed = strlen(tmp) + 1; |
*s1 = realloc(*s1, needed); |
|
if (NULL == *s1) { |
/* No string lived here previously, or we failed to |
* make a copy of it, either way there's nothing we |
* can do. */ |
if (NULL == *orig) { |
cli_errno = CL_ENOMEM; |
return -1; |
} |
/* We can't even allocate enough size to restore the |
* saved copy, just give up */ |
*s1 = realloc(*s1, strlen(orig) + 1); |
if (NULL == *s1) { |
free(tmp); |
free(orig); |
cli_errno = CL_ENOMEM; |
return -1; |
} |
/* Give the string back as we found it */ |
memset(*s1, 0, sizeof(*s1)); |
memcpy(*s1, orig, strlen(orig) + 1); |
free(tmp); |
free(orig); |
cli_errno = CL_ENOMEM; |
return 0; |
} |
|
/* Ok, great, we have enough room */ |
memset(*s1, 0, sizeof(*s1)); |
memcpy(*s1, tmp, needed); |
free(tmp); |
|
/* Free tmp only if s1 was reallocated instead of allocated */ |
if (NULL != orig) |
free(orig); |
|
if (skipped) { |
/* s1 was bigger than PATH_MAX when expanded, however part |
* of the string was printed. Tell the caller not to use it */ |
cli_errno = CL_ETOOBIG; |
return -1; |
} |
|
/* Success! */ |
cli_errno = CL_EOK; |
return (int) needed; |
} |
|
/* Ported from FBSD strtok.c 8.1 (Berkeley) 6/4/93 */ |
char * cli_strtok_r(char *s, const char *delim, char **last) |
{ |
273,10 → 183,7 |
if (NULL == usr->cwd) |
snprintf(usr->cwd, PATH_MAX, "(unknown)"); |
|
if (1 < cli_psprintf(&usr->prompt, "%s # ", usr->cwd)) { |
cli_error(cli_errno, "Failed to set prompt"); |
return 1; |
} |
asprintf(&usr->prompt, "%s # ", usr->cwd); |
|
return 0; |
} |