String stuff that should be in stdlib but isn't.

Dependents:   X10Svr SSDP_Server

Committer:
WiredHome
Date:
Wed Feb 27 18:22:04 2019 +0000
Revision:
3:bc30d348f5b4
Parent:
2:c7a3039893cb
Fix the venerable off-by-one error; if the two strings are adjacent it was detecting a false overlap.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
WiredHome 0:6d899ce93ea0 1
WiredHome 0:6d899ce93ea0 2 #include "SW_String.h"
WiredHome 0:6d899ce93ea0 3
WiredHome 2:c7a3039893cb 4 #define DEBUG "SWst"
WiredHome 2:c7a3039893cb 5 #include <cstdio>
WiredHome 2:c7a3039893cb 6 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
WiredHome 2:c7a3039893cb 7 #define DBG(x, ...) std::printf("[DBG %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 2:c7a3039893cb 8 #define WARN(x, ...) std::printf("[WRN %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 2:c7a3039893cb 9 #define ERR(x, ...) std::printf("[ERR %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 2:c7a3039893cb 10 #define INFO(x, ...) std::printf("[INF %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 2:c7a3039893cb 11 #else
WiredHome 2:c7a3039893cb 12 #define DBG(x, ...)
WiredHome 2:c7a3039893cb 13 #define WARN(x, ...)
WiredHome 2:c7a3039893cb 14 #define ERR(x, ...)
WiredHome 2:c7a3039893cb 15 #define INFO(x, ...)
WiredHome 2:c7a3039893cb 16 #endif
WiredHome 2:c7a3039893cb 17
WiredHome 1:65bc379d8cd0 18 /// A more secure version of strcat
WiredHome 1:65bc379d8cd0 19 ///
WiredHome 1:65bc379d8cd0 20 /// This function is like a wrapper on strcat, to first validate the concatination
WiredHome 1:65bc379d8cd0 21 /// and then if all parameters appear good, it will call strcat. It will not
WiredHome 1:65bc379d8cd0 22 /// permit overlapping source and destination.
WiredHome 1:65bc379d8cd0 23 ///
WiredHome 1:65bc379d8cd0 24 /// If there is an error, no concatination is performed.
WiredHome 1:65bc379d8cd0 25 ///
WiredHome 1:65bc379d8cd0 26 /// @note This has a different return value than the normal strcat.
WiredHome 1:65bc379d8cd0 27 ///
WiredHome 1:65bc379d8cd0 28 /// @param[out] dst is a pointer to the start of the destination buffer (not necessarily
WiredHome 1:65bc379d8cd0 29 /// where the next string will appear).
WiredHome 1:65bc379d8cd0 30 /// @param[in] dstSize defines the size of the destination buffer.
WiredHome 1:65bc379d8cd0 31 /// @param[in] src is a pointer to the source.
WiredHome 1:65bc379d8cd0 32 ///
WiredHome 1:65bc379d8cd0 33 /// @returns
WiredHome 1:65bc379d8cd0 34 /// - 0 = no error
WiredHome 1:65bc379d8cd0 35 /// - -1 = destination pointer invalid
WiredHome 1:65bc379d8cd0 36 /// - -2 = source is too big to append into the destination
WiredHome 1:65bc379d8cd0 37 /// - -3 = overlap between src and dst
WiredHome 1:65bc379d8cd0 38 ///
WiredHome 1:65bc379d8cd0 39 int strcat_s(char * dst, size_t dstSize, const char * src) {
WiredHome 2:c7a3039893cb 40 if (dst == NULL) {
WiredHome 2:c7a3039893cb 41 ERR("strcat_s FAIL destination == NULL");
WiredHome 1:65bc379d8cd0 42 return -1;
WiredHome 2:c7a3039893cb 43 }
WiredHome 1:65bc379d8cd0 44 if (src == NULL || *src == '\0')
WiredHome 1:65bc379d8cd0 45 return 0; // done, that was easy.
WiredHome 3:bc30d348f5b4 46 // [Source ....
WiredHome 3:bc30d348f5b4 47 // [Destination ... ]
WiredHome 3:bc30d348f5b4 48 if (src >= dst && src < (dst + dstSize)) {
WiredHome 2:c7a3039893cb 49 ERR("strcat_s FAIL source overlaps destination");
WiredHome 1:65bc379d8cd0 50 return -3;
WiredHome 2:c7a3039893cb 51 }
WiredHome 1:65bc379d8cd0 52 int dstLen = strlen(dst);
WiredHome 1:65bc379d8cd0 53 int srcLen = strlen(src);
WiredHome 3:bc30d348f5b4 54 // [Source ..... +srcLen]
WiredHome 3:bc30d348f5b4 55 // [Destination + dstSize]
WiredHome 2:c7a3039893cb 56 if (src + srcLen >= dst && src + srcLen <= dst + dstSize) {
WiredHome 2:c7a3039893cb 57 ERR("strcat_s FAIL source + length overlaps destination");
WiredHome 1:65bc379d8cd0 58 return -3;
WiredHome 2:c7a3039893cb 59 }
WiredHome 3:bc30d348f5b4 60 // [Source length > freespace]
WiredHome 3:bc30d348f5b4 61 // [Destination ... \0[freespace]]
WiredHome 2:c7a3039893cb 62 if (dstLen + srcLen > dstSize) {
WiredHome 2:c7a3039893cb 63 ERR("strcat_s FAIL dstLen + srcLen > size");
WiredHome 1:65bc379d8cd0 64 return -2;
WiredHome 2:c7a3039893cb 65 }
WiredHome 1:65bc379d8cd0 66 strcat(dst, src);
WiredHome 1:65bc379d8cd0 67 return 0;
WiredHome 1:65bc379d8cd0 68 }
WiredHome 1:65bc379d8cd0 69
WiredHome 1:65bc379d8cd0 70
WiredHome 1:65bc379d8cd0 71 /// A more secure version of strcpy
WiredHome 1:65bc379d8cd0 72 ///
WiredHome 1:65bc379d8cd0 73 /// This function is like a wrapper on strcpy, to first validate the concatination
WiredHome 1:65bc379d8cd0 74 /// and then if all parameters appear good, it will call strcpy. It will not
WiredHome 1:65bc379d8cd0 75 /// permit overlapping source and destination.
WiredHome 1:65bc379d8cd0 76 ///
WiredHome 1:65bc379d8cd0 77 /// If there is an error, no copy is performed.
WiredHome 1:65bc379d8cd0 78 ///
WiredHome 1:65bc379d8cd0 79 /// @note This has a different return value than the normal strcpy.
WiredHome 1:65bc379d8cd0 80 ///
WiredHome 1:65bc379d8cd0 81 /// @param[out] dst is a pointer to the start of the destination buffer.
WiredHome 1:65bc379d8cd0 82 /// @param[in] dstSize defines the size of the destination buffer.
WiredHome 1:65bc379d8cd0 83 /// @param[in] src is a pointer to the source.
WiredHome 1:65bc379d8cd0 84 ///
WiredHome 1:65bc379d8cd0 85 /// @returns
WiredHome 1:65bc379d8cd0 86 /// - 0 = no error
WiredHome 1:65bc379d8cd0 87 /// - -1 = destination pointer invalid
WiredHome 1:65bc379d8cd0 88 /// - -2 = source is too big to append into the destination
WiredHome 1:65bc379d8cd0 89 /// - -3 = overlap between src and dst
WiredHome 1:65bc379d8cd0 90 ///
WiredHome 1:65bc379d8cd0 91 int strcpy_s(char * dst, size_t dstSize, const char * src) {
WiredHome 2:c7a3039893cb 92 if (dst == NULL) {
WiredHome 2:c7a3039893cb 93 ERR("strcpy_s FAIL destination == NULL");
WiredHome 1:65bc379d8cd0 94 return -1;
WiredHome 2:c7a3039893cb 95 }
WiredHome 1:65bc379d8cd0 96 if (src == NULL || *src == '\0') {
WiredHome 1:65bc379d8cd0 97 *dst = '\0';
WiredHome 1:65bc379d8cd0 98 return 0; // done, that was easy.
WiredHome 1:65bc379d8cd0 99 }
WiredHome 3:bc30d348f5b4 100 if (src >= dst && src < dst + dstSize) {
WiredHome 2:c7a3039893cb 101 ERR("strcpy_s FAIL source overlaps destination");
WiredHome 1:65bc379d8cd0 102 return -3;
WiredHome 2:c7a3039893cb 103 }
WiredHome 1:65bc379d8cd0 104 int srcLen = strlen(src);
WiredHome 2:c7a3039893cb 105 if (src + srcLen >= dst && src + srcLen <= dst + dstSize) {
WiredHome 2:c7a3039893cb 106 ERR("strcpy_s FAIL source + length overlaps destination");
WiredHome 1:65bc379d8cd0 107 return -3;
WiredHome 2:c7a3039893cb 108 }
WiredHome 2:c7a3039893cb 109 if (srcLen > dstSize) {
WiredHome 2:c7a3039893cb 110 ERR("strcpy_s FAIL dstLen + srcLen > size");
WiredHome 1:65bc379d8cd0 111 return -2;
WiredHome 2:c7a3039893cb 112 }
WiredHome 1:65bc379d8cd0 113 strcpy(dst, src);
WiredHome 1:65bc379d8cd0 114 return 0;
WiredHome 1:65bc379d8cd0 115 }
WiredHome 1:65bc379d8cd0 116
WiredHome 1:65bc379d8cd0 117
WiredHome 0:6d899ce93ea0 118 /// sw_tolower exists because not all compiler libraries have this function
WiredHome 0:6d899ce93ea0 119 ///
WiredHome 0:6d899ce93ea0 120 /// This takes a character and if it is upper-case, it converts it to
WiredHome 0:6d899ce93ea0 121 /// lower-case and returns it.
WiredHome 0:6d899ce93ea0 122 ///
WiredHome 0:6d899ce93ea0 123 /// @note an alternate means would be a 256-entry lookup table. Very fast...
WiredHome 0:6d899ce93ea0 124 ///
WiredHome 0:6d899ce93ea0 125 /// @param a is the character to convert
WiredHome 0:6d899ce93ea0 126 /// @returns the lower case equivalent to a
WiredHome 0:6d899ce93ea0 127 ///
WiredHome 0:6d899ce93ea0 128 char sw_tolower(char a) {
WiredHome 0:6d899ce93ea0 129 if (a >= 'A' && a <= 'Z')
WiredHome 0:6d899ce93ea0 130 return (a - 'A' + 'a');
WiredHome 0:6d899ce93ea0 131 else
WiredHome 0:6d899ce93ea0 132 return a;
WiredHome 0:6d899ce93ea0 133 }
WiredHome 0:6d899ce93ea0 134
WiredHome 0:6d899ce93ea0 135 /// sw_strnicmp exists because not all compiler libraries have this function.
WiredHome 0:6d899ce93ea0 136 ///
WiredHome 0:6d899ce93ea0 137 /// In a case-insensitive compare, evaluate 'n' characters of the left and
WiredHome 0:6d899ce93ea0 138 /// right referenced strings.
WiredHome 0:6d899ce93ea0 139 ///
WiredHome 0:6d899ce93ea0 140 /// @note Some compilers have strnicmp, others _strnicmp, and others have C++
WiredHome 0:6d899ce93ea0 141 /// methods, which is outside the scope of this C-portable set of functions.
WiredHome 0:6d899ce93ea0 142 ///
WiredHome 0:6d899ce93ea0 143 /// @param l is a pointer to the string on the left
WiredHome 0:6d899ce93ea0 144 /// @param r is a pointer to the string on the right
WiredHome 0:6d899ce93ea0 145 /// @param n is the number of characters to compare
WiredHome 0:6d899ce93ea0 146 /// @returns -1 if l < r
WiredHome 0:6d899ce93ea0 147 /// @returns 0 if l == r
WiredHome 0:6d899ce93ea0 148 /// @returns +1 if l > r
WiredHome 0:6d899ce93ea0 149 ///
WiredHome 0:6d899ce93ea0 150 int sw_strnicmp(const char *l, const char *r, size_t n) {
WiredHome 0:6d899ce93ea0 151 int result = 0;
WiredHome 0:6d899ce93ea0 152
WiredHome 0:6d899ce93ea0 153 if (n != 0) {
WiredHome 0:6d899ce93ea0 154 do {
WiredHome 0:6d899ce93ea0 155 result = sw_tolower(*l++) - sw_tolower(*r++);
WiredHome 0:6d899ce93ea0 156 } while ((result == 0) && (*l != '\0') && (--n > 0));
WiredHome 0:6d899ce93ea0 157 }
WiredHome 0:6d899ce93ea0 158 if (result < -1)
WiredHome 0:6d899ce93ea0 159 result = -1;
WiredHome 0:6d899ce93ea0 160 else if (result > 1)
WiredHome 0:6d899ce93ea0 161 result = 1;
WiredHome 0:6d899ce93ea0 162 return result;
WiredHome 0:6d899ce93ea0 163 }
WiredHome 0:6d899ce93ea0 164
WiredHome 0:6d899ce93ea0 165
WiredHome 0:6d899ce93ea0 166 /// sw_stristr exists because not all compiler libraries have this function.
WiredHome 0:6d899ce93ea0 167 ///
WiredHome 0:6d899ce93ea0 168 /// In a case-insenstive search, try to find the needle in the haystack.
WiredHome 0:6d899ce93ea0 169 ///
WiredHome 0:6d899ce93ea0 170 /// @param haystack is a pointer to string being searched
WiredHome 0:6d899ce93ea0 171 /// @param needle is a pointer to a string to find
WiredHome 0:6d899ce93ea0 172 /// @returns a pointer to the found needle in the haystack, or NULL
WiredHome 0:6d899ce93ea0 173 ///
WiredHome 0:6d899ce93ea0 174 const char * sw_stristr(const char * haystack, const char * needle) {
WiredHome 0:6d899ce93ea0 175 while (*haystack) {
WiredHome 0:6d899ce93ea0 176 if (sw_tolower(*haystack) == sw_tolower(*needle)) {
WiredHome 0:6d899ce93ea0 177 if (sw_strnicmp(haystack, needle, strlen(needle)) == 0) {
WiredHome 0:6d899ce93ea0 178 return (char *)haystack;
WiredHome 0:6d899ce93ea0 179 }
WiredHome 0:6d899ce93ea0 180 }
WiredHome 0:6d899ce93ea0 181 haystack++;
WiredHome 0:6d899ce93ea0 182 }
WiredHome 0:6d899ce93ea0 183 return NULL;
WiredHome 0:6d899ce93ea0 184 }
WiredHome 0:6d899ce93ea0 185
WiredHome 0:6d899ce93ea0 186 /// sw_stristr exists because not all compiler libraries have this function.
WiredHome 0:6d899ce93ea0 187 ///
WiredHome 0:6d899ce93ea0 188 /// In a case-insenstive search, try to find the needle in the haystack.
WiredHome 0:6d899ce93ea0 189 ///
WiredHome 0:6d899ce93ea0 190 /// @param haystack is a pointer to string being searched
WiredHome 0:6d899ce93ea0 191 /// @param needle is a pointer to a string to find
WiredHome 0:6d899ce93ea0 192 /// @returns a pointer to the found needle in the haystack, or NULL
WiredHome 0:6d899ce93ea0 193 ///
WiredHome 0:6d899ce93ea0 194 char * sw_stristr(char * haystack, const char * needle) {
WiredHome 0:6d899ce93ea0 195 while (*haystack) {
WiredHome 0:6d899ce93ea0 196 if (sw_tolower(*haystack) == sw_tolower(*needle)) {
WiredHome 0:6d899ce93ea0 197 if (sw_strnicmp(haystack, needle, strlen(needle)) == 0) {
WiredHome 0:6d899ce93ea0 198 return (char *)haystack;
WiredHome 0:6d899ce93ea0 199 }
WiredHome 0:6d899ce93ea0 200 }
WiredHome 0:6d899ce93ea0 201 haystack++;
WiredHome 0:6d899ce93ea0 202 }
WiredHome 0:6d899ce93ea0 203 return NULL;
WiredHome 0:6d899ce93ea0 204 }