string.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. /*++
  2. Copyright (c) 2012 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. string.c
  5. Abstract:
  6. This module implements common string manipulation functions used by the
  7. kernel.
  8. Author:
  9. Evan Green 24-Jul-2012
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include "rtlp.h"
  17. //
  18. // ---------------------------------------------------------------- Definitions
  19. //
  20. //
  21. // ----------------------------------------------- Internal Function Prototypes
  22. //
  23. //
  24. // ------------------------------------------------------ Data Type Definitions
  25. //
  26. //
  27. // -------------------------------------------------------------------- Globals
  28. //
  29. //
  30. // ------------------------------------------------------------------ Functions
  31. //
  32. RTL_API
  33. ULONG
  34. RtlStringCopy (
  35. PSTR Destination,
  36. PSTR Source,
  37. ULONG BufferSize
  38. )
  39. /*++
  40. Routine Description:
  41. This routine copies a string from one buffer to another, including the NULL
  42. terminator.
  43. Arguments:
  44. Destination - Supplies a pointer to the buffer where the string will be
  45. copied to.
  46. Source - Supplies a pointer to the string to copy.
  47. BufferSize - Supplies the size of the destination buffer.
  48. Return Value:
  49. Returns the number of bytes copied, including the NULL terminator. If the
  50. source string is longer than the destination buffer, the string will be
  51. truncated but still NULL terminated.
  52. --*/
  53. {
  54. ULONG ByteIndex;
  55. ASSERT(BufferSize != 0);
  56. for (ByteIndex = 0; ByteIndex < BufferSize; ByteIndex += 1) {
  57. Destination[ByteIndex] = Source[ByteIndex];
  58. if (Source[ByteIndex] == STRING_TERMINATOR) {
  59. break;
  60. }
  61. }
  62. if (ByteIndex == BufferSize) {
  63. ByteIndex -= 1;
  64. }
  65. //
  66. // Terminate the string in case the source was too long.
  67. //
  68. Destination[ByteIndex] = STRING_TERMINATOR;
  69. return ByteIndex + 1;
  70. }
  71. RTL_API
  72. VOID
  73. RtlStringReverse (
  74. PSTR String,
  75. PSTR StringEnd
  76. )
  77. /*++
  78. Routine Description:
  79. This routine reverses the contents of a string. For example, the string
  80. "abcd" would get reversed to "dcba".
  81. Arguments:
  82. String - Supplies a pointer to the beginning of the string to reverse.
  83. StringEnd - Supplies a pointer to one beyond the end of the string. That is,
  84. this pointer points to the first byte *not* in the string.
  85. Return Value:
  86. None.
  87. --*/
  88. {
  89. ULONG Length;
  90. ULONG Position;
  91. UCHAR SwapSpace;
  92. Length = StringEnd - String;
  93. //
  94. // Work from the left towards the middle, swapping characters with their
  95. // positions on the other extreme. The truncation of Length / 2 is okay
  96. // because odd length strings do not need their middle byte swapped.
  97. //
  98. for (Position = 0; Position < (Length / 2); Position += 1) {
  99. SwapSpace = String[Position];
  100. String[Position] = String[Length - Position - 1];
  101. String[Length - Position - 1] = SwapSpace;
  102. }
  103. return;
  104. }
  105. RTL_API
  106. ULONG
  107. RtlStringLength (
  108. PSTR String
  109. )
  110. /*++
  111. Routine Description:
  112. This routine determines the length of the given string, not including its
  113. NULL terminator.
  114. Arguments:
  115. String - Supplies a pointer to the beginning of the string.
  116. Return Value:
  117. Returns the length of the string, not including the NULL terminator.
  118. --*/
  119. {
  120. ULONG Length;
  121. Length = 0;
  122. while (*String != STRING_TERMINATOR) {
  123. Length += 1;
  124. String += 1;
  125. }
  126. return Length;
  127. }
  128. RTL_API
  129. BOOL
  130. RtlAreStringsEqual (
  131. PSTR String1,
  132. PSTR String2,
  133. ULONG MaxLength
  134. )
  135. /*++
  136. Routine Description:
  137. This routine determines if the contents of two strings are equal, up to a
  138. maximum number of characters.
  139. Arguments:
  140. String1 - Supplies a pointer to the first string to compare.
  141. String2 - Supplies a pointer to the second string to compare.
  142. MaxLength - Supplies the minimum of either string's buffer size.
  143. Return Value:
  144. TRUE if the strings are equal up to the maximum length.
  145. FALSE if the strings differ in some way.
  146. --*/
  147. {
  148. if (String1 == String2) {
  149. return TRUE;
  150. }
  151. while ((*String1 != STRING_TERMINATOR) &&
  152. (*String2 != STRING_TERMINATOR) &&
  153. (MaxLength != 0)) {
  154. if (*String1 != *String2) {
  155. return FALSE;
  156. }
  157. String1 += 1;
  158. String2 += 1;
  159. MaxLength -= 1;
  160. }
  161. if ((MaxLength != 0) && (*String1 != *String2)) {
  162. return FALSE;
  163. }
  164. return TRUE;
  165. }
  166. RTL_API
  167. BOOL
  168. RtlAreStringsEqualIgnoringCase (
  169. PSTR String1,
  170. PSTR String2,
  171. ULONG MaxLength
  172. )
  173. /*++
  174. Routine Description:
  175. This routine determines if the contents of two strings are equal, up to a
  176. maximum number of characters. This routine is case insensitive.
  177. Arguments:
  178. String1 - Supplies a pointer to the first string to compare.
  179. String2 - Supplies a pointer to the second string to compare.
  180. MaxLength - Supplies the minimum of either string's buffer size.
  181. Return Value:
  182. TRUE if the strings are equal up to the maximum length.
  183. FALSE if the strings differ in some way.
  184. --*/
  185. {
  186. CHAR Character1;
  187. CHAR Character2;
  188. if (String1 == String2) {
  189. return TRUE;
  190. }
  191. while ((*String1 != STRING_TERMINATOR) &&
  192. (*String2 != STRING_TERMINATOR) &&
  193. (MaxLength != 0)) {
  194. Character1 = *String1;
  195. Character2 = *String2;
  196. if ((Character1 >= 'a') && (Character1 <= 'z')) {
  197. Character1 = Character1 - 'a' + 'A';
  198. }
  199. if ((Character2 >= 'a') && (Character2 <= 'z')) {
  200. Character2 = Character2 - 'a' + 'A';
  201. }
  202. if (Character1 != Character2) {
  203. return FALSE;
  204. }
  205. String1 += 1;
  206. String2 += 1;
  207. MaxLength -= 1;
  208. }
  209. if ((MaxLength != 0) && (*String1 != *String2)) {
  210. return FALSE;
  211. }
  212. return TRUE;
  213. }
  214. RTL_API
  215. PSTR
  216. RtlStringFindCharacter (
  217. PSTR String,
  218. CHAR Character,
  219. ULONG StringLength
  220. )
  221. /*++
  222. Routine Description:
  223. This routine searches a string for the first instance of the given
  224. character, scanning from the left.
  225. Arguments:
  226. String - Supplies a pointer to the string to search.
  227. Character - Supplies a pointer to the character to search for within the
  228. string.
  229. StringLength - Supplies the length of the string, in bytes, including the
  230. NULL terminator.
  231. Return Value:
  232. Returns a pointer to the first instance of the character on success.
  233. NULL if the character could not be found in the string.
  234. --*/
  235. {
  236. //
  237. // Search the string for the character as long as the end of the string
  238. // is not reached according to a NULL terminator or the string length.
  239. //
  240. while ((StringLength != 0) && (*String != STRING_TERMINATOR)) {
  241. if (*String == Character) {
  242. return String;
  243. }
  244. String += 1;
  245. StringLength -= 1;
  246. }
  247. return NULL;
  248. }
  249. RTL_API
  250. PSTR
  251. RtlStringFindCharacterRight (
  252. PSTR String,
  253. CHAR Character,
  254. ULONG StringLength
  255. )
  256. /*++
  257. Routine Description:
  258. This routine searches a string for the first instance of the given
  259. character, scanning from the right backwards. The function will search
  260. starting at the NULL terminator or string length, whichever comes first.
  261. Arguments:
  262. String - Supplies a pointer to the string to search.
  263. Character - Supplies a pointer to the character to search for within the
  264. string.
  265. StringLength - Supplies the length of the string, in bytes, including the
  266. NULL terminator.
  267. Return Value:
  268. Returns a pointer to the first instance of the character on success.
  269. NULL if the character could not be found in the string.
  270. --*/
  271. {
  272. PSTR Current;
  273. if ((String == NULL) || (StringLength == 0)) {
  274. return NULL;
  275. }
  276. //
  277. // Find the end of the string.
  278. //
  279. Current = String;
  280. while ((*Current != STRING_TERMINATOR) &&
  281. ((UINTN)Current - (UINTN)String < StringLength)) {
  282. Current += 1;
  283. }
  284. //
  285. // Now walk backwards looking for the character.
  286. //
  287. while (Current != String) {
  288. if (*Current == Character) {
  289. return Current;
  290. }
  291. Current -= 1;
  292. }
  293. if (*Current == Character) {
  294. return String;
  295. }
  296. return NULL;
  297. }
  298. RTL_API
  299. PSTR
  300. RtlStringSearch (
  301. PSTR InputString,
  302. UINTN InputStringLength,
  303. PSTR QueryString,
  304. UINTN QueryStringLength
  305. )
  306. /*++
  307. Routine Description:
  308. This routine searches a string for the first instance of the given string
  309. within it.
  310. Arguments:
  311. InputString - Supplies a pointer to the string to search.
  312. InputStringLength - Supplies the length of the string, in bytes, including
  313. the NULL terminator.
  314. QueryString - Supplies a pointer to the null terminated string to search
  315. for.
  316. QueryStringLength - Supplies the length of the query string in bytes
  317. including the null terminator.
  318. Return Value:
  319. Returns a pointer to the first instance of the string on success.
  320. NULL if the character could not be found in the string.
  321. --*/
  322. {
  323. size_t BadCharacterShift[MAX_UCHAR + 1];
  324. int Character;
  325. size_t LastIndex;
  326. size_t ScanIndex;
  327. if ((QueryString == NULL) || (InputString == NULL)) {
  328. return NULL;
  329. }
  330. if (QueryStringLength <= 1) {
  331. return (char *)InputString;
  332. }
  333. if (InputStringLength < QueryStringLength) {
  334. return NULL;
  335. }
  336. InputStringLength -= 1;
  337. QueryStringLength -= 1;
  338. //
  339. // Initialize the bad shift table assuming that no character exists in the
  340. // query string, and thus the search can be advanced by the entire query
  341. // string.
  342. //
  343. for (ScanIndex = 0; ScanIndex <= MAX_UCHAR; ScanIndex += 1) {
  344. BadCharacterShift[ScanIndex] = QueryStringLength;
  345. }
  346. //
  347. // Now find the last occurrence of each character and save it in the shift
  348. // table.
  349. //
  350. LastIndex = QueryStringLength - 1;
  351. for (ScanIndex = 0; ScanIndex < LastIndex; ScanIndex += 1) {
  352. Character = (UCHAR)(QueryString[ScanIndex]);
  353. BadCharacterShift[Character] = LastIndex - ScanIndex;
  354. }
  355. //
  356. // Search the query string.
  357. //
  358. while (InputStringLength >= QueryStringLength) {
  359. //
  360. // Scan from the end.
  361. //
  362. ScanIndex = LastIndex;
  363. while (InputString[ScanIndex] == QueryString[ScanIndex]) {
  364. if (ScanIndex == 0) {
  365. return (PSTR)InputString;
  366. }
  367. ScanIndex -= 1;
  368. }
  369. //
  370. // Move on to a new position. Skip based on the last character of the
  371. // input no matter where the mismatch is.
  372. //
  373. Character = (UCHAR)(InputString[LastIndex]);
  374. InputStringLength -= BadCharacterShift[Character];
  375. InputString += BadCharacterShift[Character];
  376. }
  377. return NULL;
  378. }
  379. //
  380. // --------------------------------------------------------- Internal Functions
  381. //