PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
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.

833 lines
22KB

  1. /**************************************************************************
  2. *
  3. * Copyright 2008-2018 by Andrey Butok. FNET Community.
  4. *
  5. ***************************************************************************
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License"); you may
  8. * not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. *
  19. ***************************************************************************
  20. *
  21. * Standard functions implementation.
  22. *
  23. ***************************************************************************/
  24. #include "fnet.h"
  25. #include "fnet_stdlib.h"
  26. static fnet_uint32_t fnet_rand_seed; /* Used by fnet_rand()*/
  27. #if !FNET_CFG_OVERLOAD_MEMCPY
  28. /************************************************************************
  29. * DESCRIPTION:
  30. *************************************************************************/
  31. #if 0
  32. /* Slowest && Smallest */
  33. void fnet_memcpy( FNET_COMP_PACKED_VAR void *dest, FNET_COMP_PACKED_VAR const void *src, fnet_size_t n )
  34. {
  35. const fnet_uint8_t *p = (fnet_uint8_t *)src;
  36. fnet_uint8_t *q = (fnet_uint8_t *)dest;
  37. for (n++; --n; )
  38. {
  39. *q++ = *p++;
  40. }
  41. }
  42. #elif 0 /* Faster. */
  43. void fnet_memcpy (FNET_COMP_PACKED_VAR void *dest, FNET_COMP_PACKED_VAR const void *src, fnet_size_t n)
  44. {
  45. fnet_size_t longs;
  46. fnet_size_t bytes;
  47. FNET_COMP_PACKED_VAR fnet_uint32_t *dpl = (fnet_uint32_t *)dest;
  48. FNET_COMP_PACKED_VAR fnet_uint32_t *spl = (fnet_uint32_t *)src;
  49. fnet_uint8_t *dpb, *spb;
  50. bytes = (n & 0x3);
  51. longs = ((n - bytes) >> 2);
  52. for (longs++; --longs;)
  53. {
  54. *dpl++ = *spl++;
  55. }
  56. dpb = (fnet_uint8_t *)dpl;
  57. spb = (fnet_uint8_t *)spl;
  58. for (bytes++; --bytes;)
  59. {
  60. *dpb++ = *spb++;
  61. }
  62. }
  63. #else /* Fastest & Biggest. */
  64. void fnet_memcpy(FNET_COMP_PACKED_VAR void *to_ptr, FNET_COMP_PACKED_VAR const void *from_ptr, fnet_size_t number_of_bytes)
  65. {
  66. const fnet_uint8_t *from8_ptr = (const fnet_uint8_t *) from_ptr;
  67. fnet_uint8_t *to8_ptr = (fnet_uint8_t *) to_ptr;
  68. FNET_COMP_PACKED_VAR const fnet_uint16_t *from16_ptr = (const fnet_uint16_t *) from_ptr;
  69. FNET_COMP_PACKED_VAR fnet_uint16_t *to16_ptr = (fnet_uint16_t *) to_ptr;
  70. FNET_COMP_PACKED_VAR const fnet_uint32_t *from32_ptr = (const fnet_uint32_t *) from_ptr;
  71. FNET_COMP_PACKED_VAR fnet_uint32_t *to32_ptr = (fnet_uint32_t *) to_ptr;
  72. fnet_index_t loops;
  73. /*
  74. * The copying is optimized to avoid alignment problems, and attempts
  75. * to copy 32bit numbers optimally.
  76. */
  77. if (number_of_bytes > 3u)
  78. {
  79. /* Try to align source on word */
  80. if (((fnet_uint32_t)from_ptr & 1u) != 0u)
  81. {
  82. from8_ptr = (const fnet_uint8_t *) from_ptr;
  83. to8_ptr = (fnet_uint8_t *) to_ptr;
  84. *to8_ptr++ = *from8_ptr++;
  85. from_ptr = from8_ptr;
  86. to_ptr = to8_ptr;
  87. --number_of_bytes;
  88. }
  89. /* Try to align source on longword */
  90. if ((((fnet_uint32_t)from_ptr) & 2u) != 0u)
  91. {
  92. from16_ptr = (const fnet_uint16_t *) from_ptr;
  93. to16_ptr = (fnet_uint16_t *) to_ptr;
  94. *to16_ptr++ = *from16_ptr++;
  95. from_ptr = from16_ptr;
  96. to_ptr = to16_ptr;
  97. number_of_bytes -= 2u;
  98. }
  99. from32_ptr = (const fnet_uint32_t *) from_ptr;
  100. to32_ptr = (fnet_uint32_t *) to_ptr;
  101. /*
  102. ** To increase performance a bit, we will copy 64 bytes (16 * longwords) sequentially
  103. ** This gets less instruction cycles.
  104. */
  105. for (loops = (number_of_bytes >> 6u); loops > 0u; loops--)
  106. {
  107. /* copy 16 longwords */
  108. *to32_ptr++ = *from32_ptr++;
  109. *to32_ptr++ = *from32_ptr++;
  110. *to32_ptr++ = *from32_ptr++;
  111. *to32_ptr++ = *from32_ptr++;
  112. *to32_ptr++ = *from32_ptr++;
  113. *to32_ptr++ = *from32_ptr++;
  114. *to32_ptr++ = *from32_ptr++;
  115. *to32_ptr++ = *from32_ptr++;
  116. *to32_ptr++ = *from32_ptr++;
  117. *to32_ptr++ = *from32_ptr++;
  118. *to32_ptr++ = *from32_ptr++;
  119. *to32_ptr++ = *from32_ptr++;
  120. *to32_ptr++ = *from32_ptr++;
  121. *to32_ptr++ = *from32_ptr++;
  122. *to32_ptr++ = *from32_ptr++;
  123. *to32_ptr++ = *from32_ptr++;
  124. }
  125. /* Now, write the rest of bytes */
  126. for (loops = ((number_of_bytes >> 2) & 0xFu); loops > 0u; loops--)
  127. {
  128. *to32_ptr++ = *from32_ptr++;
  129. }
  130. from_ptr = from32_ptr;
  131. to_ptr = to32_ptr;
  132. }
  133. /* Copy all remaining bytes */
  134. if ((number_of_bytes & 2u) != 0u)
  135. {
  136. from16_ptr = (const fnet_uint16_t *) from_ptr;
  137. to16_ptr = (fnet_uint16_t *) to_ptr;
  138. *to16_ptr++ = *from16_ptr++;
  139. from_ptr = from16_ptr;
  140. to_ptr = to16_ptr;
  141. }
  142. if ((number_of_bytes & 1u) != 0u)
  143. {
  144. * (fnet_uint8_t *) to_ptr = * (const fnet_uint8_t *) from_ptr;
  145. }
  146. }
  147. #endif
  148. #endif
  149. /************************************************************************
  150. * DESCRIPTION: Copy function to other location.
  151. * Used for relocate function from Flash to RAM
  152. *
  153. *************************************************************************/
  154. void *fnet_memcpy_func(void *to_buf_ptr, const void *from_func_ptr, fnet_size_t to_buf_size)
  155. {
  156. fnet_memcpy(to_buf_ptr, (void *)FNET_CPU_INSTRUCTION_TO_ADDR(from_func_ptr), to_buf_size);
  157. return (void *)FNET_CPU_ADDR_TO_INSTRUCTION(to_buf_ptr);
  158. }
  159. /************************************************************************
  160. * DESCRIPTION:
  161. *************************************************************************/
  162. void fnet_memset( void *dest, fnet_uint8_t value, fnet_size_t n )
  163. {
  164. /* Not optimized */
  165. fnet_uint8_t *sp = (fnet_uint8_t *)dest;
  166. while(n)
  167. {
  168. *sp++ = (fnet_uint8_t)value;
  169. n--;
  170. }
  171. }
  172. /************************************************************************
  173. * DESCRIPTION: Same as "fnet_memset( void *s, 0, unsigned n )"
  174. *************************************************************************/
  175. void fnet_memset_zero( void *dest, fnet_size_t n )
  176. {
  177. /* Not optimized */
  178. fnet_uint8_t *sp = (fnet_uint8_t *)dest;
  179. while(n)
  180. {
  181. *sp++ = 0u;
  182. n--;
  183. }
  184. }
  185. /************************************************************************
  186. * DESCRIPTION: Compare two memory regions and return zero if they are identical,
  187. * non-zero otherwise. If count is zero, return zero.
  188. *************************************************************************/
  189. fnet_int32_t fnet_memcmp(const void *src1, const void *src2, fnet_size_t count )
  190. {
  191. const fnet_uint8_t *p1 = (const fnet_uint8_t *)src1;
  192. const fnet_uint8_t *p2 = (const fnet_uint8_t *)src2;
  193. fnet_int32_t result = 0;
  194. while(count)
  195. {
  196. result = (fnet_int32_t)(*p1 - *p2);
  197. if(result != 0)
  198. {
  199. break;
  200. }
  201. count--;
  202. ++p1;
  203. ++p2;
  204. }
  205. return result;
  206. }
  207. /************************************************************************
  208. * DESCRIPTION:
  209. *************************************************************************/
  210. fnet_int32_t fnet_strcmp( const fnet_char_t *str1, const fnet_char_t *str2 )
  211. {
  212. /* No checks for 0 */
  213. const fnet_char_t *s1p = str1;
  214. const fnet_char_t *s2p = str2;
  215. while(*s2p != '\0')
  216. {
  217. if(*s1p != *s2p)
  218. {
  219. break;
  220. }
  221. ++s1p;
  222. ++s2p;
  223. }
  224. return (fnet_int32_t)(*s1p - *s2p);
  225. }
  226. /************************************************************************
  227. * DESCRIPTION: Calculates the length of a string.
  228. *************************************************************************/
  229. fnet_size_t fnet_strlen (const fnet_char_t *str)
  230. {
  231. const fnet_char_t *s = str;
  232. fnet_size_t len = 0U;
  233. if(s)
  234. {
  235. while (*s++ != '\0')
  236. {
  237. len++;
  238. }
  239. }
  240. return len;
  241. }
  242. /************************************************************************
  243. * DESCRIPTION: Calculate the length of a fixed-size string.
  244. *************************************************************************/
  245. fnet_size_t fnet_strnlen (const fnet_char_t *str, fnet_size_t max_len)
  246. {
  247. const fnet_char_t *s = str;
  248. fnet_size_t len = 0U;
  249. if(s)
  250. {
  251. while (*s++ != '\0')
  252. {
  253. if(max_len == len)
  254. {
  255. break;
  256. }
  257. else
  258. {
  259. len++;
  260. }
  261. }
  262. }
  263. return len;
  264. }
  265. /************************************************************************
  266. * DESCRIPTION:
  267. *************************************************************************/
  268. void fnet_strcat (fnet_char_t *dest, const fnet_char_t *src)
  269. {
  270. fnet_char_t *dp;
  271. const fnet_char_t *sp = src;
  272. if ((dest != 0) && (src != 0))
  273. {
  274. dp = &dest[fnet_strlen(dest)];
  275. while (*sp != '\0')
  276. {
  277. *dp++ = *sp++;
  278. }
  279. *dp = '\0';
  280. }
  281. }
  282. /************************************************************************
  283. * DESCRIPTION:
  284. *************************************************************************/
  285. void fnet_strlcat (fnet_char_t *dest, const fnet_char_t *src, fnet_size_t n)
  286. {
  287. fnet_char_t *dp;
  288. const fnet_char_t *sp = src;
  289. if ((dest != 0) && (src != 0) && (n > 0U))
  290. {
  291. dp = &dest[fnet_strlen(dest)];
  292. while((*sp != '\0') && (n > 0u))
  293. {
  294. *dp++ = *sp++;
  295. n--;
  296. }
  297. *dp = '\0';
  298. }
  299. }
  300. /************************************************************************
  301. * DESCRIPTION:
  302. *************************************************************************/
  303. void fnet_strcpy (fnet_char_t *dest, const fnet_char_t *src)
  304. {
  305. fnet_char_t *dp = dest;
  306. const fnet_char_t *sp = src;
  307. if ((dest != 0) && (src != 0))
  308. {
  309. while (*sp != '\0')
  310. {
  311. *dp++ = *sp++;
  312. }
  313. *dp = '\0';
  314. }
  315. }
  316. /************************************************************************
  317. * DESCRIPTION:
  318. *************************************************************************/
  319. void fnet_strlcpy( fnet_char_t *dest, const fnet_char_t *src, fnet_size_t n )
  320. {
  321. fnet_char_t *dp = dest;
  322. const fnet_char_t *sp = src;
  323. if((dest != 0) && (src != 0) && (n > 0u))
  324. {
  325. while((*sp != '\0') && (n-- > 0u))
  326. {
  327. *dp++ = *sp++;
  328. }
  329. *dp = '\0';
  330. }
  331. }
  332. /************************************************************************
  333. * DESCRIPTION: The function fnet_strrchr() returns a pointer to the last
  334. * occurrence of chr in str, or NULL if no match is found.
  335. *************************************************************************/
  336. fnet_char_t *fnet_strrchr(const fnet_char_t *str, fnet_char_t chr )
  337. {
  338. const fnet_char_t *p = str;
  339. const fnet_char_t *q = 0;
  340. fnet_char_t c = chr;
  341. fnet_char_t ch = *p++;
  342. while(ch)
  343. {
  344. if(ch == c)
  345. {
  346. q = p - 1;
  347. }
  348. ch = *p++;
  349. }
  350. if(q)
  351. {
  352. return (fnet_char_t *)(q);
  353. }
  354. return (c ? FNET_NULL : (fnet_char_t *)(p - 1));
  355. }
  356. /************************************************************************
  357. * DESCRIPTION: The function fnet_strchr() returns a pointer to the first
  358. * occurence of chr in str, or 0 if chr is not found.
  359. *************************************************************************/
  360. fnet_char_t *fnet_strchr( const fnet_char_t *str, fnet_char_t chr )
  361. {
  362. const fnet_char_t *p = str;
  363. fnet_char_t c = chr;
  364. fnet_char_t ch = *p++;
  365. while(ch)
  366. {
  367. if(ch == c)
  368. {
  369. return (fnet_char_t *)(p - 1);
  370. }
  371. ch = *p++;
  372. }
  373. return (fnet_char_t *)(c ? FNET_NULL : (p - 1));
  374. }
  375. /************************************************************************
  376. * DESCRIPTION: The function fnet_strstr() returns a pointer to the first
  377. * occurrence of substr in str, or 0 if no match is found.
  378. * If the length of pat is zero, then fnet_strstr() will
  379. * simply return str.
  380. *************************************************************************/
  381. fnet_char_t *fnet_strstr( const fnet_char_t *str, const fnet_char_t *substr )
  382. {
  383. const fnet_char_t *s1 = str;
  384. const fnet_char_t *p1 = substr;
  385. fnet_uint8_t firstc, c1, c2;
  386. if((substr == 0) || (!((firstc = *p1++) != 0u)) )
  387. {
  388. return (fnet_char_t *)(str);
  389. }
  390. c1 = *s1++;
  391. while(c1)
  392. {
  393. if(c1 == firstc)
  394. {
  395. const fnet_char_t *s2 = s1;
  396. const fnet_char_t *p2 = p1;
  397. while(((c1 = *s2++) == (c2 = *p2++)) && c1)
  398. {}
  399. if(!c2)
  400. {
  401. return ((fnet_char_t *)(s1 - 1));
  402. }
  403. }
  404. c1 = *s1++;
  405. }
  406. return (0);
  407. }
  408. /************************************************************************
  409. * DESCRIPTION: The fnet_strncmp() function compares at most count characters
  410. * of str1 and str2.
  411. *************************************************************************/
  412. fnet_int32_t fnet_strncmp( const fnet_char_t *str1, const fnet_char_t *str2, fnet_size_t n )
  413. {
  414. const fnet_char_t *p1 = str1;
  415. const fnet_char_t *p2 = str2;
  416. fnet_uint8_t c1, c2;
  417. n++;
  418. while(--n)
  419. {
  420. if((c1 = *p1++) != (c2 = *p2++))
  421. {
  422. return (fnet_int32_t)(c1 - c2);
  423. }
  424. else if(!c1)
  425. {
  426. break;
  427. }
  428. else
  429. {}
  430. }
  431. return (0);
  432. }
  433. /************************************************************************
  434. * DESCRIPTION:
  435. *************************************************************************/
  436. fnet_uint32_t fnet_strtoul (const fnet_char_t *str, fnet_char_t **ptr, fnet_size_t base)
  437. {
  438. fnet_uint32_t rvalue;
  439. fnet_bool_t err;
  440. fnet_bool_t neg;
  441. fnet_char_t c;
  442. fnet_char_t *endp;
  443. fnet_char_t *startp;
  444. rvalue = 0u;
  445. err = FNET_FALSE;
  446. neg = FNET_FALSE;
  447. /* Check for invalid arguments */
  448. if ((str == 0) || (base == 1u) || (base > 36u))
  449. {
  450. if (ptr != 0)
  451. {
  452. *ptr = (fnet_char_t *)str;
  453. }
  454. return 0u;
  455. }
  456. /* Skip leading white spaces */
  457. for (startp = (fnet_char_t *)str; ((*startp == ' ') || (*startp == '\t')) ; ++startp)
  458. {}
  459. /* Check for notations */
  460. switch (startp[0])
  461. {
  462. case '0':
  463. if ((startp[1] == 'x') || (startp[1] == 'X'))
  464. {
  465. if ((base == 0u) || (base == 16u))
  466. {
  467. base = 16u;
  468. startp = &startp[2];
  469. }
  470. }
  471. break;
  472. case '-':
  473. neg = FNET_TRUE;
  474. startp = &startp[1];
  475. break;
  476. default:
  477. break;
  478. }
  479. if (base == 0u)
  480. {
  481. base = 10u;
  482. }
  483. /* Check for invalid chars in str */
  484. for ( endp = startp; (err == FNET_FALSE) && ((c = (*endp)) != '\0') && (!((*endp == ' ') || (*endp == '\t'))); ++endp)
  485. {
  486. /* Check for 0..9,Aa-Zz */
  487. if (!(((c >= '0') && (c <= '9')) ||
  488. ((c >= 'A') && (c <= 'Z')) ||
  489. ((c >= 'a') && (c <= 'z'))))
  490. {
  491. err = FNET_TRUE;
  492. }
  493. else
  494. {
  495. /* Convert fnet_char_t to num in 0..36 */
  496. if ((c >= '0') && (c <= '9')) /* Is digit.*/
  497. {
  498. c = c - '0';
  499. }
  500. else
  501. {
  502. if ((c >= 'A') && (c <= 'Z')) /* Is upper.*/
  503. {
  504. c = c - 'A' + 10u;
  505. }
  506. else
  507. {
  508. c = c - 'a' + 10u;
  509. }
  510. }
  511. /* check c against base */
  512. if (c >= base)
  513. {
  514. err = FNET_TRUE;
  515. }
  516. else
  517. {
  518. if (neg)
  519. {
  520. rvalue = (rvalue * base) - (fnet_uint32_t)c;
  521. }
  522. else
  523. {
  524. rvalue = (rvalue * base) + (fnet_uint32_t)c;
  525. }
  526. }
  527. }
  528. }
  529. /* Upon exit, endp points to the character at which valid info */
  530. /* STOPS. No chars including and beyond endp are used. */
  531. if (ptr != 0)
  532. {
  533. *ptr = endp;
  534. }
  535. if (err)
  536. {
  537. if (ptr != 0)
  538. {
  539. *ptr = (fnet_char_t *)str;
  540. }
  541. return 0u;
  542. }
  543. else
  544. {
  545. return rvalue;
  546. }
  547. }
  548. /************************************************************************
  549. * DESCRIPTION: This function converts an uppercase letter to the corresponding
  550. * lowercase letter.
  551. *************************************************************************/
  552. fnet_char_t fnet_tolower( fnet_char_t to_lower )
  553. {
  554. if((to_lower >= 'A') && (to_lower <= 'Z'))
  555. {
  556. return (fnet_uint8_t)(to_lower + 0x20u);
  557. }
  558. return to_lower;
  559. }
  560. /************************************************************************
  561. * DESCRIPTION: The fnet_strcasecmp() function compares the two strings s1
  562. * and s2, ignoring the case of the characters. It returns an
  563. * integer less than, equal to, or greater than zero if s1 is found,
  564. * respectively, to be less than, to match, or be greater than s2.
  565. *************************************************************************/
  566. fnet_int32_t fnet_strcasecmp( const fnet_char_t *str1, const fnet_char_t *str2 )
  567. {
  568. fnet_uint8_t c1, c2;
  569. while(1)
  570. {
  571. c1 = fnet_tolower(*str1++);
  572. c2 = fnet_tolower(*str2++);
  573. if(c1 < c2)
  574. {
  575. return -1;
  576. }
  577. if(c1 > c2)
  578. {
  579. return 1;
  580. }
  581. if(c1 == 0u)
  582. {
  583. return 0;
  584. }
  585. }
  586. }
  587. /************************************************************************
  588. * DESCRIPTION:
  589. *************************************************************************/
  590. fnet_int32_t fnet_strcmp_splitter( const fnet_char_t *in_str, const fnet_char_t *name, fnet_char_t splitter)
  591. {
  592. fnet_int32_t result;
  593. /* No checks for 0 */
  594. const fnet_char_t *s1p = in_str;
  595. const fnet_char_t *s2p = name;
  596. while (*s2p == ' ')
  597. {
  598. s2p++; /* Strip leading spaces */
  599. }
  600. while (*s2p == splitter)
  601. {
  602. s2p++; /* Strip heading slash */
  603. }
  604. while (*s1p == ' ')
  605. {
  606. s1p++; /* Strip leading spaces */
  607. }
  608. /* Special case for root folder.*/
  609. if((*s2p == '\0') && (*s1p == splitter))
  610. {
  611. result = 0;
  612. }
  613. else
  614. {
  615. while (*s1p == splitter)
  616. {
  617. s1p++; /* Strip heading slash */
  618. }
  619. while((*s2p != '\0') && (*s1p == *s2p))
  620. {
  621. ++s1p;
  622. ++s2p;
  623. if (*s1p == splitter)
  624. {
  625. break; /* next element */
  626. }
  627. }
  628. if(*s1p == splitter)
  629. {
  630. result = 0;
  631. }
  632. else
  633. {
  634. result = (fnet_int32_t )(*s1p - *s2p);
  635. }
  636. }
  637. return result;
  638. }
  639. /************************************************************************
  640. * DESCRIPTION: Breaks a string into a sequence of tokens.
  641. *************************************************************************/
  642. fnet_char_t *fnet_strtok_r(fnet_char_t *str, const fnet_char_t *delimiter, fnet_char_t **last)
  643. {
  644. const fnet_char_t *spanp;
  645. fnet_char_t c;
  646. fnet_char_t sc;
  647. fnet_char_t *tok;
  648. if ((str == FNET_NULL) && ((str = *last) == FNET_NULL))
  649. {
  650. return (FNET_NULL);
  651. }
  652. /*
  653. * Skip leading delimiters.
  654. */
  655. CONT:
  656. c = (*str++);
  657. spanp = delimiter;
  658. while( (sc = (*spanp++)) != 0u)
  659. {
  660. if (c == sc)
  661. {
  662. goto CONT;
  663. }
  664. }
  665. if (c == 0u) /* No non-delimiter characters */
  666. {
  667. *last = FNET_NULL;
  668. return (FNET_NULL);
  669. }
  670. tok = str - 1;
  671. /*
  672. * Scan token.
  673. */
  674. for (;;)
  675. {
  676. c = (*str++);
  677. spanp = delimiter;
  678. do
  679. {
  680. if ((sc = (*spanp++)) == c)
  681. {
  682. if (c == 0u)
  683. {
  684. str = FNET_NULL;
  685. }
  686. else
  687. {
  688. str[-1] = 0u;
  689. }
  690. *last = str;
  691. return (tok);
  692. }
  693. }
  694. while (sc != 0u);
  695. }
  696. /* Not reached.*/
  697. }
  698. /************************************************************************
  699. * DESCRIPTION: Generates a pseudo-random number.
  700. *************************************************************************/
  701. fnet_uint32_t fnet_rand(void)
  702. {
  703. #if 0 /* original */
  704. fnet_rand_seed = fnet_rand_seed * 1103515245u + 12345u;
  705. return((fnet_uint32_t)(fnet_rand_seed >> 16u) % (FNET_RAND_MAX + 1u));
  706. #else /* Park-Miller minimum random number generator (Comm ACM Oct 1988 p1192-1201, Vol 31 Num 10) */
  707. fnet_uint64_t const a = 16807; /* 7^5 (a primitive root modulo M31) */
  708. fnet_uint64_t const m = 2147483647; /* 2^31-1 (a Mersenne prime M31) */
  709. fnet_uint64_t tmp;
  710. tmp = fnet_rand_seed * a;
  711. fnet_rand_seed = (fnet_uint32_t)(tmp % m);
  712. return(fnet_rand_seed);
  713. #endif
  714. }
  715. /************************************************************************
  716. * DESCRIPTION: Initializes the pseudo-random number generator.
  717. *************************************************************************/
  718. void fnet_srand(fnet_uint32_t seed)
  719. {
  720. fnet_rand_seed += seed;
  721. }