String stuff that should be in stdlib but isn't.
Dependents: X10Svr SSDP_Server
SW_String.cpp@1:65bc379d8cd0, 2017-04-11 (annotated)
- Committer:
- WiredHome
- Date:
- Tue Apr 11 18:42:07 2017 +0000
- Revision:
- 1:65bc379d8cd0
- Parent:
- 0:6d899ce93ea0
- Child:
- 2:c7a3039893cb
Added a custom secure version of strcpy (strcpy_s) and strcat (strcat_s).
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
WiredHome | 0:6d899ce93ea0 | 1 | |
WiredHome | 0:6d899ce93ea0 | 2 | |
WiredHome | 0:6d899ce93ea0 | 3 | #include "SW_String.h" |
WiredHome | 0:6d899ce93ea0 | 4 | |
WiredHome | 1:65bc379d8cd0 | 5 | /// A more secure version of strcat |
WiredHome | 1:65bc379d8cd0 | 6 | /// |
WiredHome | 1:65bc379d8cd0 | 7 | /// This function is like a wrapper on strcat, to first validate the concatination |
WiredHome | 1:65bc379d8cd0 | 8 | /// and then if all parameters appear good, it will call strcat. It will not |
WiredHome | 1:65bc379d8cd0 | 9 | /// permit overlapping source and destination. |
WiredHome | 1:65bc379d8cd0 | 10 | /// |
WiredHome | 1:65bc379d8cd0 | 11 | /// If there is an error, no concatination is performed. |
WiredHome | 1:65bc379d8cd0 | 12 | /// |
WiredHome | 1:65bc379d8cd0 | 13 | /// @note This has a different return value than the normal strcat. |
WiredHome | 1:65bc379d8cd0 | 14 | /// |
WiredHome | 1:65bc379d8cd0 | 15 | /// @param[out] dst is a pointer to the start of the destination buffer (not necessarily |
WiredHome | 1:65bc379d8cd0 | 16 | /// where the next string will appear). |
WiredHome | 1:65bc379d8cd0 | 17 | /// @param[in] dstSize defines the size of the destination buffer. |
WiredHome | 1:65bc379d8cd0 | 18 | /// @param[in] src is a pointer to the source. |
WiredHome | 1:65bc379d8cd0 | 19 | /// |
WiredHome | 1:65bc379d8cd0 | 20 | /// @returns |
WiredHome | 1:65bc379d8cd0 | 21 | /// - 0 = no error |
WiredHome | 1:65bc379d8cd0 | 22 | /// - -1 = destination pointer invalid |
WiredHome | 1:65bc379d8cd0 | 23 | /// - -2 = source is too big to append into the destination |
WiredHome | 1:65bc379d8cd0 | 24 | /// - -3 = overlap between src and dst |
WiredHome | 1:65bc379d8cd0 | 25 | /// |
WiredHome | 1:65bc379d8cd0 | 26 | int strcat_s(char * dst, size_t dstSize, const char * src) { |
WiredHome | 1:65bc379d8cd0 | 27 | if (dst == NULL) |
WiredHome | 1:65bc379d8cd0 | 28 | return -1; |
WiredHome | 1:65bc379d8cd0 | 29 | if (src == NULL || *src == '\0') |
WiredHome | 1:65bc379d8cd0 | 30 | return 0; // done, that was easy. |
WiredHome | 1:65bc379d8cd0 | 31 | if (src >= dst && src <= dst + dstSize) |
WiredHome | 1:65bc379d8cd0 | 32 | return -3; |
WiredHome | 1:65bc379d8cd0 | 33 | int dstLen = strlen(dst); |
WiredHome | 1:65bc379d8cd0 | 34 | int srcLen = strlen(src); |
WiredHome | 1:65bc379d8cd0 | 35 | if (src + srcLen >= dst && src + srcLen <= dst + dstSize) |
WiredHome | 1:65bc379d8cd0 | 36 | return -3; |
WiredHome | 1:65bc379d8cd0 | 37 | if (dstLen + srcLen > dstSize) |
WiredHome | 1:65bc379d8cd0 | 38 | return -2; |
WiredHome | 1:65bc379d8cd0 | 39 | strcat(dst, src); |
WiredHome | 1:65bc379d8cd0 | 40 | return 0; |
WiredHome | 1:65bc379d8cd0 | 41 | } |
WiredHome | 1:65bc379d8cd0 | 42 | |
WiredHome | 1:65bc379d8cd0 | 43 | |
WiredHome | 1:65bc379d8cd0 | 44 | /// A more secure version of strcpy |
WiredHome | 1:65bc379d8cd0 | 45 | /// |
WiredHome | 1:65bc379d8cd0 | 46 | /// This function is like a wrapper on strcpy, to first validate the concatination |
WiredHome | 1:65bc379d8cd0 | 47 | /// and then if all parameters appear good, it will call strcpy. It will not |
WiredHome | 1:65bc379d8cd0 | 48 | /// permit overlapping source and destination. |
WiredHome | 1:65bc379d8cd0 | 49 | /// |
WiredHome | 1:65bc379d8cd0 | 50 | /// If there is an error, no copy is performed. |
WiredHome | 1:65bc379d8cd0 | 51 | /// |
WiredHome | 1:65bc379d8cd0 | 52 | /// @note This has a different return value than the normal strcpy. |
WiredHome | 1:65bc379d8cd0 | 53 | /// |
WiredHome | 1:65bc379d8cd0 | 54 | /// @param[out] dst is a pointer to the start of the destination buffer. |
WiredHome | 1:65bc379d8cd0 | 55 | /// @param[in] dstSize defines the size of the destination buffer. |
WiredHome | 1:65bc379d8cd0 | 56 | /// @param[in] src is a pointer to the source. |
WiredHome | 1:65bc379d8cd0 | 57 | /// |
WiredHome | 1:65bc379d8cd0 | 58 | /// @returns |
WiredHome | 1:65bc379d8cd0 | 59 | /// - 0 = no error |
WiredHome | 1:65bc379d8cd0 | 60 | /// - -1 = destination pointer invalid |
WiredHome | 1:65bc379d8cd0 | 61 | /// - -2 = source is too big to append into the destination |
WiredHome | 1:65bc379d8cd0 | 62 | /// - -3 = overlap between src and dst |
WiredHome | 1:65bc379d8cd0 | 63 | /// |
WiredHome | 1:65bc379d8cd0 | 64 | int strcpy_s(char * dst, size_t dstSize, const char * src) { |
WiredHome | 1:65bc379d8cd0 | 65 | if (dst == NULL) |
WiredHome | 1:65bc379d8cd0 | 66 | return -1; |
WiredHome | 1:65bc379d8cd0 | 67 | if (src == NULL || *src == '\0') { |
WiredHome | 1:65bc379d8cd0 | 68 | *dst = '\0'; |
WiredHome | 1:65bc379d8cd0 | 69 | return 0; // done, that was easy. |
WiredHome | 1:65bc379d8cd0 | 70 | } |
WiredHome | 1:65bc379d8cd0 | 71 | if (src >= dst && src <= dst + dstSize) |
WiredHome | 1:65bc379d8cd0 | 72 | return -3; |
WiredHome | 1:65bc379d8cd0 | 73 | int srcLen = strlen(src); |
WiredHome | 1:65bc379d8cd0 | 74 | if (src + srcLen >= dst && src + srcLen <= dst + dstSize) |
WiredHome | 1:65bc379d8cd0 | 75 | return -3; |
WiredHome | 1:65bc379d8cd0 | 76 | if (srcLen > dstSize) |
WiredHome | 1:65bc379d8cd0 | 77 | return -2; |
WiredHome | 1:65bc379d8cd0 | 78 | strcpy(dst, src); |
WiredHome | 1:65bc379d8cd0 | 79 | return 0; |
WiredHome | 1:65bc379d8cd0 | 80 | } |
WiredHome | 1:65bc379d8cd0 | 81 | |
WiredHome | 1:65bc379d8cd0 | 82 | |
WiredHome | 0:6d899ce93ea0 | 83 | /// sw_tolower exists because not all compiler libraries have this function |
WiredHome | 0:6d899ce93ea0 | 84 | /// |
WiredHome | 0:6d899ce93ea0 | 85 | /// This takes a character and if it is upper-case, it converts it to |
WiredHome | 0:6d899ce93ea0 | 86 | /// lower-case and returns it. |
WiredHome | 0:6d899ce93ea0 | 87 | /// |
WiredHome | 0:6d899ce93ea0 | 88 | /// @note an alternate means would be a 256-entry lookup table. Very fast... |
WiredHome | 0:6d899ce93ea0 | 89 | /// |
WiredHome | 0:6d899ce93ea0 | 90 | /// @param a is the character to convert |
WiredHome | 0:6d899ce93ea0 | 91 | /// @returns the lower case equivalent to a |
WiredHome | 0:6d899ce93ea0 | 92 | /// |
WiredHome | 0:6d899ce93ea0 | 93 | char sw_tolower(char a) { |
WiredHome | 0:6d899ce93ea0 | 94 | if (a >= 'A' && a <= 'Z') |
WiredHome | 0:6d899ce93ea0 | 95 | return (a - 'A' + 'a'); |
WiredHome | 0:6d899ce93ea0 | 96 | else |
WiredHome | 0:6d899ce93ea0 | 97 | return a; |
WiredHome | 0:6d899ce93ea0 | 98 | } |
WiredHome | 0:6d899ce93ea0 | 99 | |
WiredHome | 0:6d899ce93ea0 | 100 | /// sw_strnicmp exists because not all compiler libraries have this function. |
WiredHome | 0:6d899ce93ea0 | 101 | /// |
WiredHome | 0:6d899ce93ea0 | 102 | /// In a case-insensitive compare, evaluate 'n' characters of the left and |
WiredHome | 0:6d899ce93ea0 | 103 | /// right referenced strings. |
WiredHome | 0:6d899ce93ea0 | 104 | /// |
WiredHome | 0:6d899ce93ea0 | 105 | /// @note Some compilers have strnicmp, others _strnicmp, and others have C++ |
WiredHome | 0:6d899ce93ea0 | 106 | /// methods, which is outside the scope of this C-portable set of functions. |
WiredHome | 0:6d899ce93ea0 | 107 | /// |
WiredHome | 0:6d899ce93ea0 | 108 | /// @param l is a pointer to the string on the left |
WiredHome | 0:6d899ce93ea0 | 109 | /// @param r is a pointer to the string on the right |
WiredHome | 0:6d899ce93ea0 | 110 | /// @param n is the number of characters to compare |
WiredHome | 0:6d899ce93ea0 | 111 | /// @returns -1 if l < r |
WiredHome | 0:6d899ce93ea0 | 112 | /// @returns 0 if l == r |
WiredHome | 0:6d899ce93ea0 | 113 | /// @returns +1 if l > r |
WiredHome | 0:6d899ce93ea0 | 114 | /// |
WiredHome | 0:6d899ce93ea0 | 115 | int sw_strnicmp(const char *l, const char *r, size_t n) { |
WiredHome | 0:6d899ce93ea0 | 116 | int result = 0; |
WiredHome | 0:6d899ce93ea0 | 117 | |
WiredHome | 0:6d899ce93ea0 | 118 | if (n != 0) { |
WiredHome | 0:6d899ce93ea0 | 119 | do { |
WiredHome | 0:6d899ce93ea0 | 120 | result = sw_tolower(*l++) - sw_tolower(*r++); |
WiredHome | 0:6d899ce93ea0 | 121 | } while ((result == 0) && (*l != '\0') && (--n > 0)); |
WiredHome | 0:6d899ce93ea0 | 122 | } |
WiredHome | 0:6d899ce93ea0 | 123 | if (result < -1) |
WiredHome | 0:6d899ce93ea0 | 124 | result = -1; |
WiredHome | 0:6d899ce93ea0 | 125 | else if (result > 1) |
WiredHome | 0:6d899ce93ea0 | 126 | result = 1; |
WiredHome | 0:6d899ce93ea0 | 127 | return result; |
WiredHome | 0:6d899ce93ea0 | 128 | } |
WiredHome | 0:6d899ce93ea0 | 129 | |
WiredHome | 0:6d899ce93ea0 | 130 | |
WiredHome | 0:6d899ce93ea0 | 131 | /// sw_stristr exists because not all compiler libraries have this function. |
WiredHome | 0:6d899ce93ea0 | 132 | /// |
WiredHome | 0:6d899ce93ea0 | 133 | /// In a case-insenstive search, try to find the needle in the haystack. |
WiredHome | 0:6d899ce93ea0 | 134 | /// |
WiredHome | 0:6d899ce93ea0 | 135 | /// @param haystack is a pointer to string being searched |
WiredHome | 0:6d899ce93ea0 | 136 | /// @param needle is a pointer to a string to find |
WiredHome | 0:6d899ce93ea0 | 137 | /// @returns a pointer to the found needle in the haystack, or NULL |
WiredHome | 0:6d899ce93ea0 | 138 | /// |
WiredHome | 0:6d899ce93ea0 | 139 | const char * sw_stristr(const char * haystack, const char * needle) { |
WiredHome | 0:6d899ce93ea0 | 140 | while (*haystack) { |
WiredHome | 0:6d899ce93ea0 | 141 | if (sw_tolower(*haystack) == sw_tolower(*needle)) { |
WiredHome | 0:6d899ce93ea0 | 142 | if (sw_strnicmp(haystack, needle, strlen(needle)) == 0) { |
WiredHome | 0:6d899ce93ea0 | 143 | return (char *)haystack; |
WiredHome | 0:6d899ce93ea0 | 144 | } |
WiredHome | 0:6d899ce93ea0 | 145 | } |
WiredHome | 0:6d899ce93ea0 | 146 | haystack++; |
WiredHome | 0:6d899ce93ea0 | 147 | } |
WiredHome | 0:6d899ce93ea0 | 148 | return NULL; |
WiredHome | 0:6d899ce93ea0 | 149 | } |
WiredHome | 0:6d899ce93ea0 | 150 | |
WiredHome | 0:6d899ce93ea0 | 151 | /// sw_stristr exists because not all compiler libraries have this function. |
WiredHome | 0:6d899ce93ea0 | 152 | /// |
WiredHome | 0:6d899ce93ea0 | 153 | /// In a case-insenstive search, try to find the needle in the haystack. |
WiredHome | 0:6d899ce93ea0 | 154 | /// |
WiredHome | 0:6d899ce93ea0 | 155 | /// @param haystack is a pointer to string being searched |
WiredHome | 0:6d899ce93ea0 | 156 | /// @param needle is a pointer to a string to find |
WiredHome | 0:6d899ce93ea0 | 157 | /// @returns a pointer to the found needle in the haystack, or NULL |
WiredHome | 0:6d899ce93ea0 | 158 | /// |
WiredHome | 0:6d899ce93ea0 | 159 | char * sw_stristr(char * haystack, const char * needle) { |
WiredHome | 0:6d899ce93ea0 | 160 | while (*haystack) { |
WiredHome | 0:6d899ce93ea0 | 161 | if (sw_tolower(*haystack) == sw_tolower(*needle)) { |
WiredHome | 0:6d899ce93ea0 | 162 | if (sw_strnicmp(haystack, needle, strlen(needle)) == 0) { |
WiredHome | 0:6d899ce93ea0 | 163 | return (char *)haystack; |
WiredHome | 0:6d899ce93ea0 | 164 | } |
WiredHome | 0:6d899ce93ea0 | 165 | } |
WiredHome | 0:6d899ce93ea0 | 166 | haystack++; |
WiredHome | 0:6d899ce93ea0 | 167 | } |
WiredHome | 0:6d899ce93ea0 | 168 | return NULL; |
WiredHome | 0:6d899ce93ea0 | 169 | } |