Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3365 → Rev 3366

/trunk/uspace/app/bdsh/util.c
52,6 → 52,8
#include "errors.h"
#include "util.h"
 
extern volatile int cli_errno;
 
/* some platforms do not have strdup, implement it here.
* Returns a pointer to an allocated string or NULL on failure */
char * cli_strdup(const char *s1)
59,9 → 61,12
size_t len = strlen(s1) + 1;
void *ret = malloc(len);
 
if (ret == NULL)
if (ret == NULL) {
cli_errno = CL_ENOMEM;
return (char *) NULL;
}
 
cli_errno = CL_EOK;
return (char *) memcpy(ret, s1, len);
}
 
79,54 → 84,108
 
*s1 = realloc(*s1, len);
 
if (*s1 == NULL)
if (*s1 == NULL) {
cli_errno = CL_ENOMEM;
return -1;
}
 
memset(*s1, 0, sizeof(*s1));
memcpy(*s1, s2, len);
cli_errno = CL_EOK;
return (int) len;
}
 
/* An asprintf() for concantenating paths. Allocates the system PATH_MAX value,
* expands the formatted string and re-sizes the block s1 points to accordingly.
/* 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 the length of the new s1 on success, -1 on failure. On failure, an
* attempt is made to return s1 unmodified for sanity, in this case 0 is returned.
* to indicate that s1 was not modified.
* 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.
*
* FIXME: ugly hack to get around asprintf(), if you use this, CHECK ITS VALUE! */
* 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);
 
if (NULL == tmp)
/* Don't even touch s1, not enough memory */
if (NULL == tmp) {
cli_errno = CL_ENOMEM;
return -1;
}
 
char *orig = *s1;
/* 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(tmp, base, fmt, ap);
/* 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;
}
136,8 → 195,10
char *spanp, *tok;
int c, sc;
 
if (s == NULL && (s = *last) == NULL)
if (s == NULL && (s = *last) == NULL) {
cli_errno = CL_EFAIL;
return (NULL);
}
 
cont:
c = *s++;