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

Dependents:   X10Svr SSDP_Server

Committer:
WiredHome
Date:
Sun Nov 18 04:04:48 2018 +0000
Revision:
2:c7a3039893cb
Parent:
1:65bc379d8cd0
Child:
3:bc30d348f5b4
Improve the diagnostic when debug is enabled.

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