/** dropt_strndup * * Duplicates the first n characters of a string. * * PARAMETERS: * IN s : The string to duplicate. * IN n : The maximum number of dropt_char-s to copy, excluding the * NUL-terminator. * * RETURNS: * The duplicated string, which is always NUL-terminated. The caller * is responsible for calling free() on it when no longer needed. * Returns NULL on error. */ dropt_char* dropt_strndup(const dropt_char* s, size_t n) { dropt_char* copy; size_t len = 0; assert(s != NULL); while (len < n && s[len] != DROPT_TEXT_LITERAL('\0')) { len++; } if (len + 1 < len) { /* This overflow check shouldn't be strictly necessary. len can be * at most SIZE_MAX, so SIZE_MAX + 1 can wrap around to 0, but * dropt_safe_malloc will return NULL for a 0-sized allocation. * However, favor defensive paranoia. */ return NULL; } copy = dropt_safe_malloc(len + 1 /* NUL */, sizeof *copy); if (copy != NULL) { memcpy(copy, s, len * sizeof *copy); copy[len] = DROPT_TEXT_LITERAL('\0'); } return copy; }
/** init_lookup_tables * * Initializes the sorted lookup tables in a dropt context if not * already initialized. * * PARAMETERS: * IN/OUT context : The dropt context. * Must not be NULL. */ static void init_lookup_tables(dropt_context * context) { const dropt_option * options; size_t n; assert(context != NULL); options = context->options; n = context->numOptions; if (context->sortedByLong == NULL) { context->sortedByLong = dropt_safe_malloc(n, sizeof * (context->sortedByLong)); if (context->sortedByLong != NULL) { size_t i; for (i = 0; i < n; i++) { context->sortedByLong[i].option = &options[i]; context->sortedByLong[i].context = context; } qsort(context->sortedByLong, n, sizeof * (context->sortedByLong), cmp_option_proxies_long); } } if (context->sortedByShort == NULL) { context->sortedByShort = dropt_safe_malloc(n, sizeof * (context->sortedByShort)); if (context->sortedByShort != NULL) { size_t i; for (i = 0; i < n; i++) { context->sortedByShort[i].option = &options[i]; context->sortedByShort[i].context = context; } qsort(context->sortedByShort, n, sizeof * (context->sortedByShort), cmp_option_proxies_short); } } }
/** dropt_ssopen * * Constructs a new dropt_stringstream. * * RETURNS: * An initialized dropt_stringstream. The caller is responsible for * calling either dropt_ssclose() or dropt_ssfinalize() on it when * no longer needed. * Returns NULL on error. */ dropt_stringstream * dropt_ssopen(void) { dropt_stringstream * ss = malloc(sizeof * ss); if (ss != NULL) { ss->used = 0; ss->maxSize = default_stringstream_buffer_size; ss->string = dropt_safe_malloc(ss->maxSize, sizeof * ss->string); if (ss->string == NULL) { free(ss); ss = NULL; } else { ss->string[0] = DROPT_TEXT_LITERAL('\0'); } } return ss; }
/** dropt_vasprintf * * Allocates a formatted string with vprintf semantics. * * PARAMETERS: * IN format : printf-style format specifier. Must not be NULL. * IN args : Arguments to insert into the formatted string. * * RETURNS: * The formatted string, which is always NUL-terminated. The caller * is responsible for calling free() on it when no longer needed. * Returns NULL on error. */ dropt_char * dropt_vasprintf(const dropt_char * format, va_list args) { dropt_char * s = NULL; int len; va_list argsCopy; assert(format != NULL); va_copy(argsCopy, args); len = dropt_vsnprintf(NULL, 0, format, argsCopy); va_end(argsCopy); if (len >= 0) { size_t n = len + 1 /* NUL */; s = dropt_safe_malloc(n, sizeof * s); if (s != NULL) { dropt_vsnprintf(s, n, format, args); } } return s; }