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

Dependents:   X10Svr SSDP_Server

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?

UserRevisionLine numberNew 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 }