You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

string.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. /*
  2. * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. *
  19. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. #include <stddef.h>
  25. #include <stdint.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <ctype.h>
  29. /** @file
  30. *
  31. * String functions
  32. *
  33. */
  34. /**
  35. * Fill memory region
  36. *
  37. * @v dest Destination region
  38. * @v character Fill character
  39. * @v len Length
  40. * @ret dest Destination region
  41. */
  42. void * generic_memset ( void *dest, int character, size_t len ) {
  43. uint8_t *dest_bytes = dest;
  44. while ( len-- )
  45. *(dest_bytes++) = character;
  46. return dest;
  47. }
  48. /**
  49. * Copy memory region
  50. *
  51. * @v dest Destination region
  52. * @v src Source region
  53. * @v len Length
  54. * @ret dest Destination region
  55. */
  56. void * generic_memcpy ( void *dest, const void *src, size_t len ) {
  57. const uint8_t *src_bytes = src;
  58. uint8_t *dest_bytes = dest;
  59. while ( len-- )
  60. *(dest_bytes++) = *(src_bytes++);
  61. return dest;
  62. }
  63. /**
  64. * Copy (possibly overlapping) memory region
  65. *
  66. * @v dest Destination region
  67. * @v src Source region
  68. * @v len Length
  69. * @ret dest Destination region
  70. */
  71. void * generic_memmove ( void *dest, const void *src, size_t len ) {
  72. const uint8_t *src_bytes = ( src + len );
  73. uint8_t *dest_bytes = ( dest + len );
  74. if ( dest < src )
  75. return generic_memcpy ( dest, src, len );
  76. while ( len-- )
  77. *(--dest_bytes) = *(--src_bytes);
  78. return dest;
  79. }
  80. /**
  81. * Compare memory regions
  82. *
  83. * @v first First region
  84. * @v second Second region
  85. * @v len Length
  86. * @ret diff Difference
  87. */
  88. int memcmp ( const void *first, const void *second, size_t len ) {
  89. const uint8_t *first_bytes = first;
  90. const uint8_t *second_bytes = second;
  91. int diff;
  92. while ( len-- ) {
  93. diff = ( *(second_bytes++) - *(first_bytes++) );
  94. if ( diff )
  95. return diff;
  96. }
  97. return 0;
  98. }
  99. /**
  100. * Find character within a memory region
  101. *
  102. * @v src Source region
  103. * @v character Character to find
  104. * @v len Length
  105. * @ret found Found character, or NULL if not found
  106. */
  107. void * memchr ( const void *src, int character, size_t len ) {
  108. const uint8_t *src_bytes = src;
  109. for ( ; len-- ; src_bytes++ ) {
  110. if ( *src_bytes == character )
  111. return ( ( void * ) src_bytes );
  112. }
  113. return NULL;
  114. }
  115. /**
  116. * Swap memory regions
  117. *
  118. * @v first First region
  119. * @v second Second region
  120. * @v len Length
  121. * @ret first First region
  122. */
  123. void * memswap ( void *first, void *second, size_t len ) {
  124. uint8_t *first_bytes = first;
  125. uint8_t *second_bytes = second;
  126. uint8_t temp;
  127. for ( ; len-- ; first_bytes++, second_bytes++ ) {
  128. temp = *first_bytes;
  129. *first_bytes = *second_bytes;
  130. *second_bytes = temp;
  131. }
  132. return first;
  133. }
  134. /**
  135. * Compare strings
  136. *
  137. * @v first First string
  138. * @v second Second string
  139. * @ret diff Difference
  140. */
  141. int strcmp ( const char *first, const char *second ) {
  142. return strncmp ( first, second, ~( ( size_t ) 0 ) );
  143. }
  144. /**
  145. * Compare strings
  146. *
  147. * @v first First string
  148. * @v second Second string
  149. * @v max Maximum length to compare
  150. * @ret diff Difference
  151. */
  152. int strncmp ( const char *first, const char *second, size_t max ) {
  153. const uint8_t *first_bytes = ( ( const uint8_t * ) first );
  154. const uint8_t *second_bytes = ( ( const uint8_t * ) second );
  155. int diff;
  156. for ( ; max-- ; first_bytes++, second_bytes++ ) {
  157. diff = ( *first_bytes - *second_bytes );
  158. if ( diff )
  159. return diff;
  160. if ( ! *first_bytes )
  161. return 0;
  162. }
  163. return 0;
  164. }
  165. /**
  166. * Compare case-insensitive strings
  167. *
  168. * @v first First string
  169. * @v second Second string
  170. * @ret diff Difference
  171. */
  172. int strcasecmp ( const char *first, const char *second ) {
  173. const uint8_t *first_bytes = ( ( const uint8_t * ) first );
  174. const uint8_t *second_bytes = ( ( const uint8_t * ) second );
  175. int diff;
  176. for ( ; ; first_bytes++, second_bytes++ ) {
  177. diff = ( toupper ( *first_bytes ) -
  178. toupper ( *second_bytes ) );
  179. if ( diff )
  180. return diff;
  181. if ( ! *first_bytes )
  182. return 0;
  183. }
  184. }
  185. /**
  186. * Get length of string
  187. *
  188. * @v src String
  189. * @ret len Length
  190. */
  191. size_t strlen ( const char *src ) {
  192. return strnlen ( src, ~( ( size_t ) 0 ) );
  193. }
  194. /**
  195. * Get length of string
  196. *
  197. * @v src String
  198. * @v max Maximum length
  199. * @ret len Length
  200. */
  201. size_t strnlen ( const char *src, size_t max ) {
  202. const uint8_t *src_bytes = ( ( const uint8_t * ) src );
  203. size_t len = 0;
  204. while ( max-- && *(src_bytes++) )
  205. len++;
  206. return len;
  207. }
  208. /**
  209. * Find character within a string
  210. *
  211. * @v src String
  212. * @v character Character to find
  213. * @ret found Found character, or NULL if not found
  214. */
  215. char * strchr ( const char *src, int character ) {
  216. const uint8_t *src_bytes = ( ( const uint8_t * ) src );
  217. for ( ; ; src_bytes++ ) {
  218. if ( *src_bytes == character )
  219. return ( ( char * ) src_bytes );
  220. if ( ! *src_bytes )
  221. return NULL;
  222. }
  223. }
  224. /**
  225. * Find rightmost character within a string
  226. *
  227. * @v src String
  228. * @v character Character to find
  229. * @ret found Found character, or NULL if not found
  230. */
  231. char * strrchr ( const char *src, int character ) {
  232. const uint8_t *src_bytes = ( ( const uint8_t * ) src );
  233. const uint8_t *start = src_bytes;
  234. while ( *src_bytes )
  235. src_bytes++;
  236. for ( src_bytes-- ; src_bytes >= start ; src_bytes-- ) {
  237. if ( *src_bytes == character )
  238. return ( ( char * ) src_bytes );
  239. }
  240. return NULL;
  241. }
  242. /**
  243. * Find substring
  244. *
  245. * @v haystack String
  246. * @v needle Substring
  247. * @ret found Found substring, or NULL if not found
  248. */
  249. char * strstr ( const char *haystack, const char *needle ) {
  250. size_t len = strlen ( needle );
  251. for ( ; *haystack ; haystack++ ) {
  252. if ( memcmp ( haystack, needle, len ) == 0 )
  253. return ( ( char * ) haystack );
  254. }
  255. return NULL;
  256. }
  257. /**
  258. * Copy string
  259. *
  260. * @v dest Destination string
  261. * @v src Source string
  262. * @ret dest Destination string
  263. */
  264. char * strcpy ( char *dest, const char *src ) {
  265. const uint8_t *src_bytes = ( ( const uint8_t * ) src );
  266. uint8_t *dest_bytes = ( ( uint8_t * ) dest );
  267. /* We cannot use strncpy(), since that would pad the destination */
  268. for ( ; ; src_bytes++, dest_bytes++ ) {
  269. *dest_bytes = *src_bytes;
  270. if ( ! *dest_bytes )
  271. break;
  272. }
  273. return dest;
  274. }
  275. /**
  276. * Copy string
  277. *
  278. * @v dest Destination string
  279. * @v src Source string
  280. * @v max Maximum length
  281. * @ret dest Destination string
  282. */
  283. char * strncpy ( char *dest, const char *src, size_t max ) {
  284. const uint8_t *src_bytes = ( ( const uint8_t * ) src );
  285. uint8_t *dest_bytes = ( ( uint8_t * ) dest );
  286. for ( ; max ; max--, src_bytes++, dest_bytes++ ) {
  287. *dest_bytes = *src_bytes;
  288. if ( ! *dest_bytes )
  289. break;
  290. }
  291. while ( max-- )
  292. *(dest_bytes++) = '\0';
  293. return dest;
  294. }
  295. /**
  296. * Concatenate string
  297. *
  298. * @v dest Destination string
  299. * @v src Source string
  300. * @ret dest Destination string
  301. */
  302. char * strcat ( char *dest, const char *src ) {
  303. strcpy ( ( dest + strlen ( dest ) ), src );
  304. return dest;
  305. }
  306. /**
  307. * Duplicate string
  308. *
  309. * @v src Source string
  310. * @ret dup Duplicated string, or NULL if allocation failed
  311. */
  312. char * strdup ( const char *src ) {
  313. return strndup ( src, ~( ( size_t ) 0 ) );
  314. }
  315. /**
  316. * Duplicate string
  317. *
  318. * @v src Source string
  319. * @v max Maximum length
  320. * @ret dup Duplicated string, or NULL if allocation failed
  321. */
  322. char * strndup ( const char *src, size_t max ) {
  323. size_t len = strnlen ( src, max );
  324. char *dup;
  325. dup = malloc ( len + 1 /* NUL */ );
  326. if ( dup ) {
  327. memcpy ( dup, src, len );
  328. dup[len] = '\0';
  329. }
  330. return dup;
  331. }
  332. /**
  333. * Calculate digit value
  334. *
  335. * @v character Digit character
  336. * @ret digit Digit value
  337. *
  338. * Invalid digits will be returned as a value greater than or equal to
  339. * the numeric base.
  340. */
  341. unsigned int digit_value ( unsigned int character ) {
  342. if ( character >= 'a' )
  343. return ( character - ( 'a' - 10 ) );
  344. if ( character >= 'A' )
  345. return ( character - ( 'A' - 10 ) );
  346. if ( character <= '9' )
  347. return ( character - '0' );
  348. return character;
  349. }
  350. /**
  351. * Preprocess string for strtoul() or strtoull()
  352. *
  353. * @v string String
  354. * @v negate Final value should be negated
  355. * @v base Numeric base
  356. * @ret string Remaining string
  357. */
  358. static const char * strtoul_pre ( const char *string, int *negate, int *base ) {
  359. /* Skip any leading whitespace */
  360. while ( isspace ( *string ) )
  361. string++;
  362. /* Process arithmetic sign, if present */
  363. *negate = 0;
  364. if ( *string == '-' ) {
  365. string++;
  366. *negate = 1;
  367. } else if ( *string == '+' ) {
  368. string++;
  369. }
  370. /* Process base, if present */
  371. if ( *base == 0 ) {
  372. *base = 10;
  373. if ( *string == '0' ) {
  374. string++;
  375. *base = 8;
  376. if ( ( *string & ~0x20 ) == 'X' ) {
  377. string++;
  378. *base = 16;
  379. }
  380. }
  381. }
  382. return string;
  383. }
  384. /**
  385. * Convert string to numeric value
  386. *
  387. * @v string String
  388. * @v endp End pointer (or NULL)
  389. * @v base Numeric base (or zero to autodetect)
  390. * @ret value Numeric value
  391. */
  392. unsigned long strtoul ( const char *string, char **endp, int base ) {
  393. unsigned long value = 0;
  394. unsigned int digit;
  395. int negate;
  396. /* Preprocess string */
  397. string = strtoul_pre ( string, &negate, &base );
  398. /* Process digits */
  399. for ( ; ; string++ ) {
  400. digit = digit_value ( *string );
  401. if ( digit >= ( unsigned int ) base )
  402. break;
  403. value = ( ( value * base ) + digit );
  404. }
  405. /* Negate value if, applicable */
  406. if ( negate )
  407. value = -value;
  408. /* Fill in end pointer, if applicable */
  409. if ( endp )
  410. *endp = ( ( char * ) string );
  411. return value;
  412. }
  413. /**
  414. * Convert string to numeric value
  415. *
  416. * @v string String
  417. * @v endp End pointer (or NULL)
  418. * @v base Numeric base (or zero to autodetect)
  419. * @ret value Numeric value
  420. */
  421. unsigned long long strtoull ( const char *string, char **endp, int base ) {
  422. unsigned long long value = 0;
  423. unsigned int digit;
  424. int negate;
  425. /* Preprocess string */
  426. string = strtoul_pre ( string, &negate, &base );
  427. /* Process digits */
  428. for ( ; ; string++ ) {
  429. digit = digit_value ( *string );
  430. if ( digit >= ( unsigned int ) base )
  431. break;
  432. value = ( ( value * base ) + digit );
  433. }
  434. /* Negate value if, applicable */
  435. if ( negate )
  436. value = -value;
  437. /* Fill in end pointer, if applicable */
  438. if ( endp )
  439. *endp = ( ( char * ) string );
  440. return value;
  441. }