The ups and downs of strlcpy()
The ups and downs of strlcpy()
Posted Jul 26, 2012 1:28 UTC (Thu) by nybble41 (subscriber, #55106)In reply to: The ups and downs of strlcpy() by smurf
Parent article: The ups and downs of strlcpy()
Here's a suggestion (only partly sarcastic):
typedef size_t (*strxcpy_handler_t)(char *dst, const char *src, size_t size, void *data); size_t strxcpy(char *dst, const char *src, size_t size, strxcpy_handler_t overflow_fn, void *overflow_data) { char *p; const char *q; for (p = dst, q = src; *q; ++p, ++q) { if ((p - dst) >= size) { return overflow_fn(dst, src, size, overflow_data); } *p = *q; } /* get here only if strlen(src) < size */ *p++ = '\0'; return (p - dst); } size_t strxcpy_truncate(char *dst, const char *src, size_t size, void *data) { if (size <= 0) abort(); dst[size - 1] = '\0'; return size + strlen(src + size); } size_t strxcpy_abort(char *dst, const char *src, size_t size, void *data) { abort(); return size; } if (strxcpy(dst, src, dst_size, strxcpy_truncate, NULL) >= dst_size) ...; (void)strxcpy(dst, src, dst_size, strxcpy_abort, NULL); (void)strxcpy(dst, src, dst_size, strxcpy_subst, "(input too long)"); /* ... */
Posted Jul 26, 2012 8:53 UTC (Thu)
by renox (guest, #23785)
[Link] (1 responses)
That said, one size doesn't fit all so having different function is reasonable, the biggest issue is that there is no sane default behaviour..
Posted Jul 26, 2012 16:27 UTC (Thu)
by nybble41 (subscriber, #55106)
[Link]
The strxcpy function isn't just a wrapper; it does all of the real work. The strxcpy_abort, strxcpy_truncate functions only run when an overflow condition is detected. This allows you to substitute your own preferred method of error-handling. This is actually rather similar to the way exceptions are handled in Common Lisp or Scheme programs, except that the Lisp version would use dynamic variables rather than explicit arguments for the handler code, which results in less cluttered code. Scheme-style parameters are attached to the current continuation, meaning that they're not only thread-safe, but that the bindings only affect the inner dynamic scope of the (parameterize) form, even in exceptional cases such as non-local return (like the middle example above) and even re-entry into a dynamic scope which was previously exited.
The ups and downs of strlcpy()
The ups and downs of strlcpy()
(define (default-error-handler error-value) (abort))
(define current-error-handler (make-parameter default-error-handler))
(define (do-something)
(... (if (ok? var) var ((current-error-handler) var)) ... ))
; aborts on error
(do-something)
; evaluates to #t on success, or #f on error
(let/cc return
(parameterize ([current-error-handler (lambda _ (return #f))])
(do-something)
#t)
; uses "value" in place of var on error
(parameterize ([current-error-handler (lambda _ value)])
(do-something))