Substrings with C
strn*() is a Design Bug
In the mid 90's the OpenBSD team realized that no only are strcpy() and strcat() dangerous, but that strncpy() and strncat() are also hazardus because the use of their parameters is confusing and they don't guarentee NUL-terminated strings. So OpenBSD's strlcpy() and strlcat() were born.
A quick search of cprogramming.com does not reveal a recommended way to slice a string using a start and end index like Python's very cool [start:end] operator.
Modify strlcpy()
As it turns out it's very easy to tweak strlcpy() to add this functionality:
- Add a new size_t start field to the function arguments.
- Do some pointer arithmatic on s which holds the source string pointer.
- Calculate the return value by the number of characters in the desination.
/* * Based on strlcpy by Todd C. Miller <Todd.Miller@courtesan.com> * Modified 2007 by Eric S. Radman <theman@eradman.com> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <sys/types.h> #include <string.h> /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlsub(char *dst, const char *src, size_t start, size_t siz) { char *d = dst; const char *s = src + start; size_t n = siz; /* Copy as many bytes as will fit */ if (n != start) { while (--n != 0) { if ((*d++ = *s++) == '\0') break; } } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(d - dst); /* count does not include NUL */ }
Create a corrisponding header file, and then use it just like strlcpy() with an extra parameter.
#include <string.h> #include "strlsub.h" #define SAMPLE "05/02 13:38 0:18 9 7101 $ 0.0 4006 --- 5871454" int main(void){ char field[24]; parse_test_input(); strlsub(field, SAMPLE, 42, 6); printf("Station: %s\n", field); }