LPCOpen Platform  v1.03
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
lib_str.c
Go to the documentation of this file.
1 /*
2 *********************************************************************************************************
3 * uC/LIB
4 * CUSTOM LIBRARY MODULES
5 *
6 * (c) Copyright 2004-2011; Micrium, Inc.; Weston, FL
7 *
8 * All rights reserved. Protected by international copyright laws.
9 *
10 * uC/LIB is provided in source form to registered licensees ONLY. It is
11 * illegal to distribute this source code to any third party unless you receive
12 * written permission by an authorized Micrium representative. Knowledge of
13 * the source code may NOT be used to develop a similar product.
14 *
15 * Please help us continue to provide the Embedded community with the finest
16 * software available. Your honesty is greatly appreciated.
17 *
18 * You can contact us at www.micrium.com.
19 *********************************************************************************************************
20 */
21 
22 /*
23 *********************************************************************************************************
24 *
25 * ASCII STRING MANAGEMENT
26 *
27 * Filename : lib_str.c
28 * Version : V1.35.00
29 * Programmer(s) : ITJ
30 * BAN
31 * JDH
32 *********************************************************************************************************
33 * Note(s) : (1) NO compiler-supplied standard library functions are used in library or product software.
34 *
35 * (a) ALL standard library functions are implemented in the custom library modules :
36 *
37 * (1) <Custom Library Directory>\lib_*.*
38 *
39 * (2) <Custom Library Directory>\Ports<cpu><compiler>\lib*_a.*
40 *
41 * where
42 * <Custom Library Directory> directory path for custom library software
43 * <cpu> directory name for specific processor (CPU)
44 * <compiler> directory name for specific compiler
45 *
46 * (b) Product-specific library functions are implemented in individual products.
47 *
48 *********************************************************************************************************
49 * Notice(s) : (1) The Institute of Electrical and Electronics Engineers and The Open Group, have given
50 * us permission to reprint portions of their documentation. Portions of this text are
51 * reprinted and reproduced in electronic form from the IEEE Std 1003.1, 2004 Edition,
52 * Standard for Information Technology -- Portable Operating System Interface (POSIX),
53 * The Open Group Base Specifications Issue 6, Copyright (C) 2001-2004 by the Institute
54 * of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any
55 * discrepancy between these versions and the original IEEE and The Open Group Standard,
56 * the original IEEE and The Open Group Standard is the referee document. The original
57 * Standard can be obtained online at http://www.opengroup.org/unix/online.html.
58 *********************************************************************************************************
59 */
60 
61 
62 /*
63 *********************************************************************************************************
64 * INCLUDE FILES
65 *********************************************************************************************************
66 */
67 
68 #define LIB_STR_MODULE
69 #include <lib_str.h>
70 
71 
72 /*$PAGE*/
73 /*
74 *********************************************************************************************************
75 * LOCAL DEFINES
76 *********************************************************************************************************
77 */
78 
79 
80 /*
81 *********************************************************************************************************
82 * LOCAL CONSTANTS
83 *********************************************************************************************************
84 */
85 
86 
87 /*
88 *********************************************************************************************************
89 * LOCAL DATA TYPES
90 *********************************************************************************************************
91 */
92 
93 
94 /*
95 *********************************************************************************************************
96 * LOCAL TABLES
97 *********************************************************************************************************
98 */
99 
101  (CPU_INT32U) DEF_INT_32U_MAX_VAL, /* Invalid base 0. */
102  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 1u), /* Invalid base 1. */
103  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 2u), /* 32-bit mult ovf th for base 2. */
104  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 3u), /* 32-bit mult ovf th for base 3. */
105  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 4u), /* 32-bit mult ovf th for base 4. */
106  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 5u), /* 32-bit mult ovf th for base 5. */
107  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 6u), /* 32-bit mult ovf th for base 6. */
108  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 7u), /* 32-bit mult ovf th for base 7. */
109  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 8u), /* 32-bit mult ovf th for base 8. */
110  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 9u), /* 32-bit mult ovf th for base 9. */
111  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 10u), /* 32-bit mult ovf th for base 10. */
112  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 11u), /* 32-bit mult ovf th for base 11. */
113  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 12u), /* 32-bit mult ovf th for base 12. */
114  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 13u), /* 32-bit mult ovf th for base 13. */
115  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 14u), /* 32-bit mult ovf th for base 14. */
116  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 15u), /* 32-bit mult ovf th for base 15. */
117  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 16u), /* 32-bit mult ovf th for base 16. */
118  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 17u), /* 32-bit mult ovf th for base 17. */
119  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 18u), /* 32-bit mult ovf th for base 18. */
120  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 19u), /* 32-bit mult ovf th for base 19. */
121  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 20u), /* 32-bit mult ovf th for base 20. */
122  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 21u), /* 32-bit mult ovf th for base 21. */
123  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 22u), /* 32-bit mult ovf th for base 22. */
124  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 23u), /* 32-bit mult ovf th for base 23. */
125  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 24u), /* 32-bit mult ovf th for base 24. */
126  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 25u), /* 32-bit mult ovf th for base 25. */
127  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 26u), /* 32-bit mult ovf th for base 26. */
128  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 27u), /* 32-bit mult ovf th for base 27. */
129  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 28u), /* 32-bit mult ovf th for base 28. */
130  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 29u), /* 32-bit mult ovf th for base 29. */
131  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 30u), /* 32-bit mult ovf th for base 30. */
132  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 31u), /* 32-bit mult ovf th for base 31. */
133  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 32u), /* 32-bit mult ovf th for base 32. */
134  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 33u), /* 32-bit mult ovf th for base 33. */
135  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 34u), /* 32-bit mult ovf th for base 34. */
136  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 35u), /* 32-bit mult ovf th for base 35. */
137  (CPU_INT32U)(DEF_INT_32U_MAX_VAL / 36u) /* 32-bit mult ovf th for base 36. */
138 };
139 
140 
141 /*
142 *********************************************************************************************************
143 * LOCAL GLOBAL VARIABLES
144 *********************************************************************************************************
145 */
146 
147 
148 /*$PAGE*/
149 /*
150 *********************************************************************************************************
151 * LOCAL FUNCTION PROTOTYPES
152 *********************************************************************************************************
153 */
154 
155 static CPU_CHAR *Str_FmtNbr_Int32 ( CPU_INT32U nbr,
156  CPU_INT08U nbr_dig,
157  CPU_INT08U nbr_base,
158  CPU_BOOLEAN nbr_neg,
159  CPU_CHAR lead_char,
160  CPU_BOOLEAN lower_case,
161  CPU_BOOLEAN nul,
162  CPU_CHAR *pstr);
163 
164 static CPU_INT32U Str_ParseNbr_Int32(const CPU_CHAR *pstr,
165  CPU_CHAR **pstr_next,
166  CPU_INT08U nbr_base,
167  CPU_BOOLEAN nbr_signed,
168  CPU_BOOLEAN *pnbr_neg);
169 
170 
171 /*
172 *********************************************************************************************************
173 * LOCAL CONFIGURATION ERRORS
174 *********************************************************************************************************
175 */
176 
177 
178 /*$PAGE*/
179 /*
180 *********************************************************************************************************
181 * Str_Len()
182 *
183 * Description : Calculate length of a string.
184 *
185 * Argument(s) : pstr Pointer to string (see Note #1).
186 *
187 * Return(s) : Length of string; number of characters in string before terminating NULL character
188 * (see Note #2b1).
189 *
190 * Caller(s) : Application.
191 *
192 * Note(s) : (1) String buffer NOT modified.
193 *
194 * (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strlen() : DESCRIPTION' states that :
195 *
196 * (1) "The strlen() function shall compute the number of bytes in the string to
197 * which 's' ('pstr') points," ...
198 * (2) "not including the terminating null byte."
199 *
200 * (b) IEEE Std 1003.1, 2004 Edition, Section 'strlen() : RETURN VALUE' states that :
201 *
202 * (1) "The strlen() function shall return the length of 's' ('pstr');" ...
203 * (2) "no return value shall be reserved to indicate an error."
204 *
205 * (3) String length calculation terminates when :
206 *
207 * (a) String pointer points to NULL.
208 * (1) String buffer overlaps with NULL address.
209 * (2) String length calculated for string up to but NOT beyond or including
210 * the NULL address.
211 *
212 * (b) Terminating NULL character found.
213 * (1) String length calculated for string up to but NOT including
214 * the NULL character (see Note #2a2).
215 *********************************************************************************************************
216 */
217 
219 {
220  CPU_SIZE_T len;
221 
222 
223  len = Str_Len_N(pstr,
224  DEF_INT_CPU_U_MAX_VAL);
225 
226  return (len);
227 }
228 
229 
230 /*$PAGE*/
231 /*
232 *********************************************************************************************************
233 * Str_Len_N()
234 *
235 * Description : Calculate length of a string, up to a maximum number of characters.
236 *
237 * Argument(s) : pstr Pointer to string (see Note #1).
238 *
239 * len_max Maximum number of characters to search (see Note #3c).
240 *
241 * Return(s) : Length of string; number of characters in string before terminating NULL character,
242 * if terminating NULL character found (see Note #2b1).
243 *
244 * Requested maximum number of characters to search,
245 * if terminating NULL character NOT found (see Note #3c).
246 *
247 * Caller(s) : Application.
248 *
249 * Note(s) : (1) String buffer NOT modified.
250 *
251 * (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strlen() : DESCRIPTION' states that :
252 *
253 * (1) "The strlen() function shall compute the number of bytes in the string to
254 * which 's' ('pstr') points," ...
255 * (2) "not including the terminating null byte."
256 *
257 * (b) IEEE Std 1003.1, 2004 Edition, Section 'strlen() : RETURN VALUE' states that :
258 *
259 * (1) "The strlen() function shall return the length of 's' ('pstr');" ...
260 * (2) "no return value shall be reserved to indicate an error."
261 *
262 * (3) String length calculation terminates when :
263 *
264 * (a) String pointer points to NULL.
265 * (1) String buffer overlaps with NULL address.
266 * (2) String length calculated for string up to but NOT beyond or including
267 * the NULL address.
268 *
269 * (b) Terminating NULL character found.
270 * (1) String length calculated for string up to but NOT including
271 * the NULL character (see Note #2a2).
272 *
273 * (c) 'len_max' number of characters searched.
274 * (1) 'len_max' number of characters does NOT include the terminating NULL character.
275 *********************************************************************************************************
276 */
277 
279  CPU_SIZE_T len_max)
280 {
281  const CPU_CHAR *pstr_len;
282  CPU_SIZE_T len;
283 
284 
285  pstr_len = pstr;
286  len = 0u;
287  while (( pstr_len != (const CPU_CHAR *) 0 ) && /* Calc str len until NULL ptr (see Note #3a) ... */
288  (*pstr_len != ( CPU_CHAR )'\0') && /* ... or NULL char found (see Note #3b) ... */
289  ( len < ( CPU_SIZE_T)len_max)) { /* ... or max nbr chars srch'd (see Note #3c). */
290  pstr_len++;
291  len++;
292  }
293 
294  return (len); /* Rtn str len (see Note #3b1). */
295 }
296 
297 
298 /*$PAGE*/
299 /*
300 *********************************************************************************************************
301 * Str_Copy()
302 *
303 * Description : Copy source string to destination string buffer.
304 *
305 * Argument(s) : pstr_dest Pointer to destination string buffer to receive source string copy (see Note #1a).
306 *
307 * pstr_src Pointer to source string to copy into destination string buffer (see Note #1b).
308 *
309 * Return(s) : Pointer to destination string, if NO error(s) [see Note #2b1].
310 *
311 * Pointer to NULL, otherwise (see Note #2b2A).
312 *
313 * Caller(s) : Application.
314 *
315 * Note(s) : (1) (a) Destination buffer size NOT validated; buffer overruns MUST be prevented by caller.
316 *
317 * (1) Destination buffer size MUST be large enough to accommodate the entire source
318 * string size including the terminating NULL character.
319 *
320 * (b) Source buffer NOT modified.
321 *
322 * (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strcpy() : DESCRIPTION' states that :
323 *
324 * (1) "The strcpy() function shall copy the string pointed to by 's2' ('pstr_src')
325 * ... into the array pointed to by 's1' ('pstr_dest')" ...
326 * (2) "(including the terminating null byte)."
327 *
328 * (b) IEEE Std 1003.1, 2004 Edition, Section 'strcpy() : RETURN VALUE' states that :
329 *
330 * (1) "The strcpy() function shall return 's1' ('pstr_dest');" ...
331 * (2) "no return value is reserved to indicate an error."
332 * (A) #### This requirement is intentionally NOT implemented in order to return
333 * NULL for any error(s).
334 *
335 * (c) IEEE Std 1003.1, 2004 Edition, Section 'strcpy() : DESCRIPTION' states that "if
336 * copying takes place between objects that overlap, the behavior is undefined".
337 *
338 * (3) String copy terminates when :
339 *
340 * (a) Destination/Source string pointer(s) are passed NULL pointers.
341 * (1) No string copy performed; NULL pointer returned.
342 *
343 * (b) Destination/Source string pointer(s) point to NULL.
344 * (1) String buffer(s) overlap with NULL address; NULL pointer returned.
345 *
346 * (c) Source string's terminating NULL character found.
347 * (1) Entire source string copied into destination string buffer (see Note #2a).
348 *********************************************************************************************************
349 */
350 
351 CPU_CHAR *Str_Copy ( CPU_CHAR *pstr_dest,
352  const CPU_CHAR *pstr_src)
353 {
354  CPU_CHAR *pstr_rtn;
355 
356 
357  pstr_rtn = Str_Copy_N(pstr_dest,
358  pstr_src,
359  DEF_INT_CPU_U_MAX_VAL);
360 
361  return (pstr_rtn);
362 }
363 
364 
365 /*$PAGE*/
366 /*
367 *********************************************************************************************************
368 * Str_Copy_N()
369 *
370 * Description : Copy source string to destination string buffer, up to a maximum number of characters.
371 *
372 * Argument(s) : pstr_dest Pointer to destination string buffer to receive source string copy (see Note #1a).
373 *
374 * pstr_src Pointer to source string to copy into destination string buffer (see Note #1b).
375 *
376 * len_max Maximum number of characters to copy (see Notes #2a2 & #3d).
377 *
378 * Return(s) : Pointer to destination string, if NO error(s) [see Note #2b1].
379 *
380 * Pointer to NULL, otherwise (see Note #2b2A).
381 *
382 * Caller(s) : Application.
383 *
384 * Note(s) : (1) (a) Destination buffer size NOT validated; buffer overruns MUST be prevented by caller.
385 *
386 * (1) Destination buffer size MUST be large enough to accommodate the entire source
387 * string size including the terminating NULL character.
388 *
389 * (b) Source string buffer NOT modified.
390 *
391 * (2) (a) (1) IEEE Std 1003.1, 2004 Edition, Section 'strncpy() : DESCRIPTION' states that :
392 *
393 * (A) "The strncpy() function shall copy ... the array pointed to by 's2'
394 * ('pstr_src') to the array pointed to by 's1' ('pstr_dest')"; ...
395 * (B) but "not more than 'n' ('len_max') bytes" ...
396 * (C) & "(bytes that follow a null byte are not copied)".
397 *
398 * (2) (A) IEEE Std 1003.1, 2004 Edition, Section 'strncpy() : DESCRIPTION' adds that
399 * "if the array pointed to by 's2' ('pstr_src') is a string that is shorter
400 * than 'n' ('len_max') bytes, null bytes shall be appended to the copy in
401 * the array pointed to by 's1' ('pstr_dest'), until 'n' ('len_max') bytes
402 * in all are written."
403 *
404 * (1) #### Since Str_Copy() limits the maximum number of characters to copy
405 * via Str_Copy_N() by the CPU's maximum number of addressable characters,
406 * this requirement is intentionally NOT implemented to avoid appending
407 * a potentially large number of unnecessary terminating NULL characters.
408 *
409 * (B) IEEE Std 1003.1, 2004 Edition, Section 'strncpy() : APPLICATION USAGE' also
410 * states that "if there is no null byte in the first 'n' ('len_max') bytes of
411 * the array pointed to by 's2' ('pstr_src'), the result is not null-terminated".
412 *
413 * (b) IEEE Std 1003.1, 2004 Edition, Section 'strncpy() : RETURN VALUE' states that :
414 *
415 * (1) "The strncpy() function shall return 's1' ('pstr_dest');" ...
416 * (2) "no return value is reserved to indicate an error."
417 * (A) #### This requirement is intentionally ignored in order to return NULL
418 * for any error(s).
419 *
420 * (c) IEEE Std 1003.1, 2004 Edition, Section 'strncpy() : DESCRIPTION' states that "if
421 * copying takes place between objects that overlap, the behavior is undefined".
422 *
423 * (3) String copy terminates when :
424 *
425 * (a) Destination/Source string pointer(s) are passed NULL pointers.
426 * (1) No string copy performed; NULL pointer returned.
427 *
428 * (b) Destination/Source string pointer(s) point to NULL.
429 * (1) String buffer(s) overlap with NULL address; NULL pointer returned.
430 *
431 * (c) Source string's terminating NULL character found.
432 * (1) Entire source string copied into destination string buffer (see Note #2a1A).
433 *
434 * (d) 'len_max' number of characters copied.
435 * (1) 'len_max' number of characters MAY include the terminating NULL character
436 * (see Note #2a1C).
437 * (2) Null copies allowed (i.e. zero-length copies).
438 * (A) No string copy performed; destination string returned (see Note #2b1).
439 *********************************************************************************************************
440 */
441 /*$PAGE*/
443  const CPU_CHAR *pstr_src,
444  CPU_SIZE_T len_max)
445 {
446  CPU_CHAR *pstr_copy_dest;
447  const CPU_CHAR *pstr_copy_src;
448  CPU_SIZE_T len_copy;
449 
450  /* Rtn NULL if str ptr(s) NULL (see Note #3a1). */
451  if (pstr_dest == (CPU_CHAR *)0) {
452  return ((CPU_CHAR *)0);
453  }
454  if (pstr_src == (const CPU_CHAR *)0) {
455  return ((CPU_CHAR *)0);
456  }
457 
458 
459  pstr_copy_dest = pstr_dest;
460  pstr_copy_src = pstr_src;
461  len_copy = 0u;
462 
463  while (( pstr_copy_dest != ( CPU_CHAR *) 0 ) && /* Copy str until NULL ptr(s) [see Note #3b] ... */
464  ( pstr_copy_src != (const CPU_CHAR *) 0 ) &&
465  (*pstr_copy_src != ( CPU_CHAR )'\0') && /* ... or NULL char found (see Note #3c); ... */
466  ( len_copy < ( CPU_SIZE_T)len_max)) { /* ... or max nbr chars copied (see Note #3d). */
467  *pstr_copy_dest = *pstr_copy_src;
468  pstr_copy_dest++;
469  pstr_copy_src++;
470  len_copy++;
471  }
472  /* Rtn NULL if NULL ptr(s) found (see Note #3b1). */
473  if ((pstr_copy_dest == ( CPU_CHAR *)0) ||
474  (pstr_copy_src == (const CPU_CHAR *)0)) {
475  return ((CPU_CHAR *)0);
476  }
477 
478  if (len_copy < len_max) { /* If copy str len < max buf len (see Note #2a2A), ... */
479  *pstr_copy_dest = (CPU_CHAR)'\0'; /* ... copy NULL char (see Note #3c1). */
480  }
481 
482 
483  return (pstr_dest); /* Rtn ptr to dest str (see Note #2b1). */
484 }
485 
486 
487 /*$PAGE*/
488 /*
489 *********************************************************************************************************
490 * Str_Cat()
491 *
492 * Description : Append concatenation string to destination string.
493 *
494 * Argument(s) : pstr_dest Pointer to destination string to append concatenation string (see Note #1a).
495 *
496 * pstr_cat Pointer to concatenation string to append to destination string (see Note #1b).
497 *
498 * Return(s) : Pointer to destination string, if NO error(s) [see Note #2b1].
499 *
500 * Pointer to NULL, otherwise (see Note #2b2A).
501 *
502 * Caller(s) : Application.
503 *
504 * Note(s) : (1) (a) Destination buffer size NOT validated; buffer overruns MUST be prevented by caller.
505 *
506 * (1) Destination buffer size MUST be large enough to accommodate the entire
507 * concatenated string size including the terminating NULL character.
508 *
509 * (b) Concatenation string buffer NOT modified.
510 *
511 * (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strcat() : DESCRIPTION' states that :
512 *
513 * (1) "The strcat() function shall append a copy of the string pointed to by 's2'
514 * ('pstr_cat') ... to the end of the string pointed to by 's1' ('pstr_dest')."
515 *
516 * (2) (A) "The initial byte of 's2' ('pstr_cat') overwrites the null byte at the
517 * end of 's1' ('pstr_dest')."
518 * (B) A "terminating null byte" is appended at the end of the concatenated
519 * destination strings.
520 *
521 * (b) IEEE Std 1003.1, 2004 Edition, Section 'strcat() : RETURN VALUE' states that :
522 *
523 * (1) "The strcat() function shall return 's1' ('pstr_dest');" ...
524 * (2) "no return value shall be reserved to indicate an error."
525 * (A) #### This requirement is intentionally NOT implemented in order to return
526 * NULL for any error(s).
527 *
528 * (c) IEEE Std 1003.1, 2004 Edition, Section 'strcat() : DESCRIPTION' states that "if
529 * copying takes place between objects that overlap, the behavior is undefined."
530 *
531 * (3) String concatenation terminates when :
532 *
533 * (a) Destination/Concatenation string pointer(s) are passed NULL pointers.
534 * (1) No string concatenation performed; NULL pointer returned.
535 *
536 * (b) Destination/Concatenation string pointer(s) point to NULL.
537 * (1) String buffer(s) overlap with NULL address; NULL pointer returned.
538 *
539 * (c) Concatenation string's terminating NULL character found.
540 * (1) Entire concatenation string appended to destination string (see Note #2a1).
541 *********************************************************************************************************
542 */
543 
544 CPU_CHAR *Str_Cat ( CPU_CHAR *pstr_dest,
545  const CPU_CHAR *pstr_cat)
546 {
547  CPU_CHAR *pstr_rtn;
548 
549 
550  pstr_rtn = Str_Cat_N(pstr_dest,
551  pstr_cat,
552  DEF_INT_CPU_U_MAX_VAL);
553 
554  return (pstr_rtn);
555 }
556 
557 
558 /*$PAGE*/
559 /*
560 *********************************************************************************************************
561 * Str_Cat_N()
562 *
563 * Description : Append concatenation string to destination string, up to a maximum number of characters.
564 *
565 * Argument(s) : pstr_dest Pointer to destination string to append concatenation string (see Note #1a).
566 *
567 * pstr_cat Pointer to concatenation string to append to destination string (see Note #1b).
568 *
569 * len_max Maximum number of characters to concatenate (see Notes #2a1B & #3d).
570 *
571 * Return(s) : Pointer to destination string, if NO error(s) [see Note #2b1].
572 *
573 * Pointer to NULL, otherwise (see Note #2b2A).
574 *
575 * Caller(s) : Application.
576 *
577 * Note(s) : (1) (a) Destination buffer size NOT validated; buffer overruns MUST be prevented by caller.
578 *
579 * (1) Destination buffer size MUST be large enough to accommodate the entire
580 * concatenated string size including the terminating NULL character.
581 *
582 * (b) Concatenation string buffer NOT modified.
583 *
584 * (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strncat() : DESCRIPTION' states that :
585 *
586 * (1) (A) "The strncat() function shall append ... the array pointed to by 's2'
587 * ('pstr_cat') to the end of the string pointed to by 's1' ('pstr_dest')" ...
588 * (B) but "not more than 'n' ('len_max') bytes".
589 *
590 * (2) (A) "The initial byte of 's2' ('pstr_cat') overwrites the null byte at the
591 * end of 's1' ('pstr_dest')."
592 * (B) "(a null byte and bytes that follow it are not appended)."
593 * (C) "A terminating null byte is always appended to the result."
594 *
595 * (b) IEEE Std 1003.1, 2004 Edition, Section 'strncat() : RETURN VALUE' states that :
596 *
597 * (1) "The strncat() function shall return 's1' ('pstr_dest');" ...
598 * (2) "no return value shall be reserved to indicate an error."
599 * (A) #### This requirement is intentionally NOT implemented in order to return
600 * NULL for any error(s).
601 *
602 * (c) IEEE Std 1003.1, 2004 Edition, Section 'strncat() : DESCRIPTION' states that "if
603 * copying takes place between objects that overlap, the behavior is undefined."
604 *
605 * (3) String concatenation terminates when :
606 *
607 * (a) Destination/Concatenation string pointer(s) are passed NULL pointers.
608 * (1) No string concatenation performed; NULL pointer returned.
609 *
610 * (b) Destination/Concatenation string pointer(s) point to NULL.
611 * (1) String buffer(s) overlap with NULL address; NULL pointer returned.
612 *
613 * (c) Concatenation string's terminating NULL character found.
614 * (1) Entire concatenation string appended to destination string (see Note #2a1A).
615 *
616 * (d) 'len_max' number of characters concatenated.
617 *
618 * (1) 'len_max' number of characters does NOT include the terminating NULL character
619 * (see Note #2a2).
620 *
621 * (2) Null concatenations allowed (i.e. zero-length concatenations).
622 * (A) No string concatenation performed; destination string returned
623 * (see Note #2b1).
624 *********************************************************************************************************
625 */
626 /*$PAGE*/
628  const CPU_CHAR *pstr_cat,
629  CPU_SIZE_T len_max)
630 {
631  CPU_CHAR *pstr_cat_dest;
632  const CPU_CHAR *pstr_cat_src;
633  CPU_SIZE_T len_cat;
634 
635  /* Rtn NULL if str ptr(s) NULL (see Note #3a1). */
636  if (pstr_dest == (CPU_CHAR *)0) {
637  return ((CPU_CHAR *)0);
638  }
639  if (pstr_cat == (const CPU_CHAR *)0) {
640  return ((CPU_CHAR *)0);
641  }
642 
643  if (len_max == 0) { /* Rtn dest str if cat len = 0 (see Note #3d2A). */
644  return ((CPU_CHAR *)pstr_dest);
645  }
646 
647 
648  pstr_cat_dest = pstr_dest;
649  while (( pstr_cat_dest != (CPU_CHAR *) 0 ) && /* Adv to end of cur dest str until NULL ptr ... */
650  (*pstr_cat_dest != (CPU_CHAR )'\0')) { /* ... or NULL char found.. */
651  pstr_cat_dest++;
652  }
653  if (pstr_cat_dest == (CPU_CHAR *)0) { /* Rtn NULL if NULL ptr found (see Note #3b1). */
654  return ((CPU_CHAR *)0);
655  }
656 
657  pstr_cat_src = pstr_cat;
658  len_cat = 0u;
659 
660  while (( pstr_cat_dest != ( CPU_CHAR *) 0 ) && /* Cat str until NULL ptr(s) [see Note #3b] ... */
661  ( pstr_cat_src != (const CPU_CHAR *) 0 ) &&
662  (*pstr_cat_src != ( CPU_CHAR )'\0') && /* ... or NULL char found (see Note #3c); ... */
663  ( len_cat < ( CPU_SIZE_T)len_max)) { /* ... or max nbr chars cat'd (see Note #3d). */
664  *pstr_cat_dest = *pstr_cat_src;
665  pstr_cat_dest++;
666  pstr_cat_src++;
667  len_cat++;
668  }
669  /* Rtn NULL if NULL ptr(s) found (see Note #3b1). */
670  if ((pstr_cat_dest == ( CPU_CHAR *)0) ||
671  (pstr_cat_src == (const CPU_CHAR *)0)) {
672  return ((CPU_CHAR *)0);
673  }
674 
675  *pstr_cat_dest = (CPU_CHAR)'\0'; /* Append NULL char (see Note #2a2C). */
676 
677 
678  return (pstr_dest); /* Rtn ptr to dest str (see Note #2b1). */
679 }
680 
681 
682 /*$PAGE*/
683 /*
684 *********************************************************************************************************
685 * Str_Cmp()
686 *
687 * Description : Determine if two strings are identical.
688 *
689 * Argument(s) : p1_str Pointer to first string (see Note #1).
690 *
691 * p2_str Pointer to second string (see Note #1).
692 *
693 * Return(s) : 0, if strings are identical (see Notes #3a1A, #3a2A, & #3b).
694 *
695 * Negative value, if 'p1_str' is less than 'p2_str' (see Notes #3a1B1, #3a2B1, & #3c).
696 *
697 * Positive value, if 'p1_str' is greater than 'p2_str' (see Notes #3a1B2, #3a2B2, & #3c).
698 *
699 * See also Note #2b.
700 *
701 * Caller(s) : Application.
702 *
703 * Note(s) : (1) String buffers NOT modified.
704 *
705 * (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strcmp() : DESCRIPTION' states that "the
706 * strcmp() function shall compare the string pointed to by 's1' ('p1_str') to the
707 * string pointed to by 's2' ('p2_str)".
708 *
709 * (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strcmp() : RETURN VALUE' states that
710 * "upon successful completion, strcmp() shall return an integer greater than,
711 * equal to, or less than 0".
712 *
713 * (2) IEEE Std 1003.1, 2004 Edition, Section 'strcmp() : DESCRIPTION' adds that "the
714 * sign of a non-zero return value shall be determined by the sign of the difference
715 * between the values of the first pair of bytes ... that differ in the strings
716 * being compared".
717 *
718 * (3) String comparison terminates when :
719 *
720 * (a) (1) (A) BOTH string pointer(s) are passed NULL pointers.
721 * (1) NULL strings identical; 0 returned.
722 *
723 * (B) (1) 'p1_str' passed a NULL pointer.
724 * (a) Return negative value of character pointed to by 'p2_str'.
725 *
726 * (2) 'p2_str' passed a NULL pointer.
727 * (a) Return positive value of character pointed to by 'p1_str'.
728 *
729 * (2) (A) BOTH strings point to NULL.
730 * (1) Strings overlap with NULL address.
731 * (2) Strings identical up to but NOT beyond or including the NULL address;
732 * 0 returned.
733 *
734 * (B) (1) 'p1_str_cmp_next' points to NULL.
735 * (a) 'p1_str' overlaps with NULL address.
736 * (b) Strings compared up to but NOT beyond or including the NULL address.
737 * (c) Return negative value of character pointed to by 'p2_str_cmp_next'.
738 *
739 * (2) 'p2_str_cmp_next' points to NULL.
740 * (a) 'p2_str' overlaps with NULL address.
741 * (b) Strings compared up to but NOT beyond or including the NULL address.
742 * (c) Return positive value of character pointed to by 'p1_str_cmp_next'.
743 *
744 * (b) Terminating NULL character found in both strings.
745 * (1) Strings identical; 0 returned.
746 * (2) Only one NULL character test required in conditional since previous condition
747 * tested character equality.
748 *
749 * (c) Non-matching characters found.
750 * (1) Return signed-integer difference of the character pointed to by 'p2_str'
751 * from the character pointed to by 'p1_str'.
752 *
753 * (4) Since 16-bit signed arithmetic is performed to calculate a non-identical comparison
754 * return value, 'CPU_CHAR' native data type size MUST be 8-bit.
755 *********************************************************************************************************
756 */
757 
758 CPU_INT16S Str_Cmp (const CPU_CHAR *p1_str,
759  const CPU_CHAR *p2_str)
760 {
761  CPU_INT16S cmp_val;
762 
763 
764  cmp_val = Str_Cmp_N(p1_str,
765  p2_str,
766  DEF_INT_CPU_U_MAX_VAL);
767 
768  return (cmp_val);
769 }
770 
771 
772 /*$PAGE*/
773 /*
774 *********************************************************************************************************
775 * Str_Cmp_N()
776 *
777 * Description : Determine if two strings are identical for up to a maximum number of characters.
778 *
779 * Argument(s) : p1_str Pointer to first string (see Note #1).
780 *
781 * p2_str Pointer to second string (see Note #1).
782 *
783 * len_max Maximum number of characters to compare (see Note #3d).
784 *
785 * Return(s) : 0, if strings are identical (see Notes #3a1A, #3a2A, #3b, & #3d).
786 *
787 * Negative value, if 'p1_str' is less than 'p2_str' (see Notes #3a1B1, #3a2B1, & #3c).
788 *
789 * Positive value, if 'p1_str' is greater than 'p2_str' (see Notes #3a1B2, #3a2B2, & #3c).
790 *
791 * See also Note #2b.
792 *
793 * Caller(s) : Application.
794 *
795 * Note(s) : (1) String buffers NOT modified.
796 *
797 * (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strncmp() : DESCRIPTION' states that :
798 *
799 * (1) "The strncmp() function shall compare ... the array pointed to by 's1' ('p1_str')
800 * to the array pointed to by 's2' ('p2_str)" ...
801 * (2) but "not more than 'n' ('len_max') bytes" of either array.
802 *
803 * (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strncmp() : RETURN VALUE' states that
804 * "upon successful completion, strncmp() shall return an integer greater than,
805 * equal to, or less than 0".
806 *
807 * (2) IEEE Std 1003.1, 2004 Edition, Section 'strncmp() : DESCRIPTION' adds that
808 * "the sign of a non-zero return value is determined by the sign of the difference
809 * between the values of the first pair of bytes ... that differ in the strings
810 * being compared".
811 *
812 * (3) String comparison terminates when :
813 *
814 * (a) (1) (A) BOTH string pointer(s) are passed NULL pointers.
815 * (1) NULL strings identical; 0 returned.
816 *
817 * (B) (1) 'p1_str' passed a NULL pointer.
818 * (a) Return negative value of character pointed to by 'p2_str'.
819 *
820 * (2) 'p2_str' passed a NULL pointer.
821 * (a) Return positive value of character pointed to by 'p1_str'.
822 *
823 * (2) (A) BOTH strings point to NULL.
824 * (1) Strings overlap with NULL address.
825 * (2) Strings identical up to but NOT beyond or including the NULL address;
826 * 0 returned.
827 *
828 * (B) (1) 'p1_str_cmp_next' points to NULL.
829 * (a) 'p1_str' overlaps with NULL address.
830 * (b) Strings compared up to but NOT beyond or including the NULL address.
831 * (c) Return negative value of character pointed to by 'p2_str_cmp_next'.
832 *
833 * (2) 'p2_str_cmp_next' points to NULL.
834 * (a) 'p2_str' overlaps with NULL address.
835 * (b) Strings compared up to but NOT beyond or including the NULL address.
836 * (c) Return positive value of character pointed to by 'p1_str_cmp_next'.
837 *
838 * (b) Terminating NULL character found in both strings.
839 * (1) Strings identical; 0 returned.
840 * (2) Only one NULL character test required in conditional since previous condition
841 * tested character equality.
842 *
843 * (c) Non-matching characters found.
844 * (1) Return signed-integer difference of the character pointed to by 'p2_str'
845 * from the character pointed to by 'p1_str'.
846 *
847 * (d) (1) 'len_max' passed a zero length.
848 * (A) Zero-length strings identical; 0 returned.
849 *
850 * (2) First 'len_max' number of characters identical.
851 * (A) Strings identical; 0 returned.
852 *
853 * See also Note #2a2.
854 *
855 * (4) Since 16-bit signed arithmetic is performed to calculate a non-identical comparison
856 * return value, 'CPU_CHAR' native data type size MUST be 8-bit.
857 *********************************************************************************************************
858 */
859 /*$PAGE*/
861  const CPU_CHAR *p2_str,
862  CPU_SIZE_T len_max)
863 {
864  const CPU_CHAR *p1_str_cmp;
865  const CPU_CHAR *p2_str_cmp;
866  const CPU_CHAR *p1_str_cmp_next;
867  const CPU_CHAR *p2_str_cmp_next;
868  CPU_INT16S cmp_val;
869  CPU_SIZE_T cmp_len;
870 
871 
872  if (len_max == 0) { /* If cmp len = 0, rtn 0 (see Note #3d1A). */
873  return (0);
874  }
875 
876  if (p1_str == (const CPU_CHAR *)0) {
877  if (p2_str == (const CPU_CHAR *)0) {
878  return (0); /* If BOTH str ptrs NULL, rtn 0 (see Note #3a1A). */
879  }
880  cmp_val = (CPU_INT16S)0 - (CPU_INT16S)(*p2_str);
881  return (cmp_val); /* If p1_str NULL, rtn neg p2_str val (see Note #3a1B1).*/
882  }
883  if (p2_str == (const CPU_CHAR *)0) {
884  cmp_val = (CPU_INT16S)(*p1_str);
885  return (cmp_val); /* If p2_str NULL, rtn pos p1_str val (see Note #3a1B2).*/
886  }
887 
888 
889  p1_str_cmp = p1_str;
890  p2_str_cmp = p2_str;
891  p1_str_cmp_next = p1_str_cmp;
892  p2_str_cmp_next = p2_str_cmp;
893  p1_str_cmp_next++;
894  p2_str_cmp_next++;
895  cmp_len = 0u;
896 
897  while ((*p1_str_cmp == *p2_str_cmp) && /* Cmp strs until non-matching chars (see Note #3c) ... */
898  (*p1_str_cmp != ( CPU_CHAR )'\0') && /* ... or NULL chars (see Note #3b) ... */
899  ( p1_str_cmp_next != (const CPU_CHAR *) 0 ) && /* ... or NULL ptr(s) found (see Note #3a2); */
900  ( p2_str_cmp_next != (const CPU_CHAR *) 0 ) &&
901  ( cmp_len < ( CPU_SIZE_T)len_max)) { /* ... or max nbr chars cmp'd (see Note #3d2). */
902  p1_str_cmp++;
903  p2_str_cmp++;
904  p1_str_cmp_next++;
905  p2_str_cmp_next++;
906  cmp_len++;
907  }
908 
909 
910  if (cmp_len == len_max) { /* If strs identical for max len nbr of chars, ... */
911  return (0); /* ... rtn 0 (see Note #3d2A). */
912  }
913 
914  if (*p1_str_cmp != *p2_str_cmp) { /* If strs NOT identical, ... */
915  /* ... calc & rtn char diff (see Note #3c1). */
916  cmp_val = (CPU_INT16S)(*p1_str_cmp) - (CPU_INT16S)(*p2_str_cmp);
917 
918  } else if (*p1_str_cmp == (CPU_CHAR)'\0') { /* If NULL char(s) found, ... */
919  cmp_val = (CPU_INT16S)0; /* ... strs identical; rtn 0 (see Note #3b). */
920 
921  } else {
922  if (p1_str_cmp_next == (const CPU_CHAR *)0) {
923  if (p2_str_cmp_next == (const CPU_CHAR *)0) { /* If BOTH next str ptrs NULL, ... */
924  cmp_val = (CPU_INT16S)0; /* ... rtn 0 (see Note #3a2A). */
925  } else { /* If p1_str_cmp_next NULL, ... */
926  /* ... rtn neg p2_str_cmp_next val (see Note #3a2B1). */
927  cmp_val = (CPU_INT16S)0 - (CPU_INT16S)(*p2_str_cmp_next);
928  }
929  } else { /* If p2_str_cmp_next NULL, ... */
930  cmp_val = (CPU_INT16S)(*p1_str_cmp_next); /* ... rtn pos p1_str_cmp_next val (see Note #3a2B2). */
931  }
932  }
933 
934 
935  return (cmp_val);
936 }
937 
938 
939 /*$PAGE*/
940 /*
941 *********************************************************************************************************
942 * Str_CmpIgnoreCase()
943 *
944 * Description : Determine if two strings are identical, ignoring case.
945 *
946 * Argument(s) : p1_str Pointer to first string (see Note #1).
947 *
948 * p2_str Pointer to second string (see Note #1).
949 *
950 * Return(s) : 0, if strings are identical (see Notes #3a1A, #3a2A, & #3b).
951 *
952 * Negative value, if 'p1_str' is less than 'p2_str' (see Notes #3a1B1, #3a2B1, & #3c).
953 *
954 * Positive value, if 'p1_str' is greater than 'p2_str' (see Notes #3a1B2, #3a2B2, & #3c).
955 *
956 * See also Note #2b.
957 *
958 * Caller(s) : Application.
959 *
960 * Note(s) : (1) String buffers NOT modified.
961 *
962 * (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strcasecmp() : DESCRIPTION' states that :
963 *
964 * (1) (A) "The strcasecmp() function shall compare ... the string pointed to by 's1'
965 * ('p1_str') to the string pointed to by 's2' ('p2_str')" ...
966 * (B) "ignoring differences in case".
967 *
968 * (2) "strcasecmp() ... shall behave as if the strings had been converted to lowercase
969 * and then a byte comparison performed."
970 *
971 * (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strcasecmp() : RETURN VALUE' states that
972 * "upon successful completion, strcasecmp() shall return an integer greater than,
973 * equal to, or less than 0".
974 *
975 * (2) IEEE Std 1003.1, 2004 Edition, Section 'strcmp() : DESCRIPTION' adds that "the
976 * sign of a non-zero return value shall be determined by the sign of the difference
977 * between the values of the first pair of bytes ... that differ in the strings
978 * being compared".
979 *
980 * (3) String comparison terminates when :
981 *
982 * (a) (1) (A) BOTH string pointer(s) are passed NULL pointers.
983 * (1) NULL strings identical; 0 returned.
984 *
985 * (B) (1) 'p1_str' passed a NULL pointer.
986 * (a) Return negative value of character pointed to by 'p2_str', converted
987 * to lower case (see Note #2a2).
988 *
989 * (2) 'p2_str' passed a NULL pointer.
990 * (a) Return positive value of character pointed to by 'p1_str', converted
991 * to lower case (see Note #2a2).
992 *
993 * (2) (A) BOTH strings point to NULL.
994 * (1) Strings overlap with NULL address.
995 * (2) Strings identical up to but NOT beyond or including the NULL address;
996 * 0 returned.
997 *
998 * (B) (1) 'p1_str_cmp_next' points to NULL.
999 * (a) 'p1_str' overlaps with NULL address.
1000 * (b) Strings compared up to but NOT beyond or including the NULL address.
1001 * (c) Return negative value of character pointed to by 'p2_str_cmp_next',
1002 * converted to lower case (see Note #2a2).
1003 *
1004 * (2) 'p2_str_cmp_next' points to NULL.
1005 * (a) 'p2_str' overlaps with NULL address.
1006 * (b) Strings compared up to but NOT beyond or including the NULL address.
1007 * (c) Return positive value of character pointed to by 'p1_str_cmp_next',
1008 * converted to lower case (see Note #2a2).
1009 *
1010 * (b) Terminating NULL character found in both strings.
1011 * (1) Strings identical; 0 returned.
1012 * (2) Only one NULL character test required in conditional since previous condition
1013 * tested character equality.
1014 *
1015 * (c) Non-matching characters found.
1016 * (1) Return signed-integer difference of the character pointed to by 'p2_str',
1017 * converted to lower case, from the character pointed to by 'p1_str', converted
1018 * to lower case.
1019 *
1020 * (4) Since 16-bit signed arithmetic is performed to calculate a non-identical comparison
1021 * return value, 'CPU_CHAR' native data type size MUST be 8-bit.
1022 *********************************************************************************************************
1023 */
1024 /*$PAGE*/
1026  const CPU_CHAR *p2_str)
1027 {
1028  CPU_INT16S cmp_val;
1029 
1030 
1031  cmp_val = Str_CmpIgnoreCase_N(p1_str,
1032  p2_str,
1033  DEF_INT_CPU_U_MAX_VAL);
1034 
1035  return (cmp_val);
1036 }
1037 
1038 
1039 /*$PAGE*/
1040 /*
1041 *********************************************************************************************************
1042 * Str_CmpIgnoreCase_N()
1043 *
1044 * Description : Determine if two strings are identical for up to a maximum number of characters,
1045 * ignoring case.
1046 *
1047 * Argument(s) : p1_str Pointer to first string (see Note #1).
1048 *
1049 * p2_str Pointer to second string (see Note #1).
1050 *
1051 * len_max Maximum number of characters to compare (see Note #3d).
1052 *
1053 * Return(s) : 0, if strings are identical (see Notes #3a1A, #3a2A, #3b, & #3d).
1054 *
1055 * Negative value, if 'p1_str' is less than 'p2_str' (see Notes #3a1B1, #3a2B1, & #3c).
1056 *
1057 * Positive value, if 'p1_str' is greater than 'p2_str' (see Notes #3a1B2, #3a2B2, & #3c).
1058 *
1059 * See also Note #2b.
1060 *
1061 * Caller(s) : Application.
1062 *
1063 * Note(s) : (1) String buffers NOT modified.
1064 *
1065 * (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strncasecmp() : DESCRIPTION' states that :
1066 *
1067 * (1) (A) "The strncasecmp() function shall compare ... the string pointed to by 's1'
1068 * ('p1_str') to the string pointed to by 's2' ('p2_str')" ...
1069 * (B) "ignoring differences in case" ...
1070 * (C) but "not more than 'n' ('len_max') bytes" of either string.
1071 *
1072 * (2) "strncasecmp() shall behave as if the strings had been converted to lowercase
1073 * and then a byte comparison performed."
1074 *
1075 * (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strncasecmp() : RETURN VALUE' states that
1076 * "upon successful completion, strncasecmp() shall return an integer greater than,
1077 * equal to, or less than 0".
1078 *
1079 * (2) IEEE Std 1003.1, 2004 Edition, Section 'strcmp() : DESCRIPTION' adds that "the
1080 * sign of a non-zero return value shall be determined by the sign of the difference
1081 * between the values of the first pair of bytes ... that differ in the strings
1082 * being compared".
1083 *
1084 * (3) String comparison terminates when :
1085 *
1086 * (a) (1) (A) BOTH string pointer(s) are passed NULL pointers.
1087 * (1) NULL strings identical; 0 returned.
1088 *
1089 * (B) (1) 'p1_str' passed a NULL pointer.
1090 * (a) Return negative value of character pointed to by 'p2_str', converted
1091 * to lower case (see Note #2a2).
1092 *
1093 * (2) 'p2_str' passed a NULL pointer.
1094 * (a) Return positive value of character pointed to by 'p1_str', converted
1095 * to lower case (see Note #2a2).
1096 *
1097 * (2) (A) BOTH strings point to NULL.
1098 * (1) Strings overlap with NULL address.
1099 * (2) Strings identical up to but NOT beyond or including the NULL address;
1100 * 0 returned.
1101 *
1102 * (B) (1) 'p1_str_cmp_next' points to NULL.
1103 * (a) 'p1_str' overlaps with NULL address.
1104 * (b) Strings compared up to but NOT beyond or including the NULL address.
1105 * (c) Return negative value of character pointed to by 'p2_str_cmp_next',
1106 * converted to lower case (see Note #2a2).
1107 *
1108 * (2) 'p2_str_cmp_next' points to NULL.
1109 * (a) 'p2_str' overlaps with NULL address.
1110 * (b) Strings compared up to but NOT beyond or including the NULL address.
1111 * (c) Return positive value of character pointed to by 'p1_str_cmp_next',
1112 * converted to lower case (see Note #2a2).
1113 *
1114 * (b) Terminating NULL character found in both strings.
1115 * (1) Strings identical; 0 returned.
1116 * (2) Only one NULL character test required in conditional since previous condition
1117 * tested character equality.
1118 *
1119 * (c) Non-matching characters found.
1120 * (1) Return signed-integer difference of the character pointed to by 'p2_str',
1121 * converted to lower case, from the character pointed to by 'p1_str', converted
1122 * to lower case.
1123 *
1124 * (d) (1) 'len_max' passed a zero length.
1125 * (A) Zero-length strings identical; 0 returned.
1126 *
1127 * (2) First 'len_max' number of characters identical.
1128 * (A) Strings identical; 0 returned.
1129 *
1130 * See also Note #2a1C.
1131 *$PAGE*
1132 * (4) Since 16-bit signed arithmetic is performed to calculate a non-identical comparison
1133 * return value, 'CPU_CHAR' native data type size MUST be 8-bit.
1134 *********************************************************************************************************
1135 */
1136 
1138  const CPU_CHAR *p2_str,
1139  CPU_SIZE_T len_max)
1140 {
1141  const CPU_CHAR *p1_str_cmp;
1142  const CPU_CHAR *p2_str_cmp;
1143  const CPU_CHAR *p1_str_cmp_next;
1144  const CPU_CHAR *p2_str_cmp_next;
1145  CPU_CHAR char_1;
1146  CPU_CHAR char_2;
1147  CPU_INT16S cmp_val;
1148  CPU_SIZE_T cmp_len;
1149 
1150 
1151  if (len_max == 0) { /* If cmp len = 0, rtn 0 (see Note #3d1A). */
1152  return (0);
1153  }
1154 
1155  if (p1_str == (const CPU_CHAR *)0) {
1156  if (p2_str == (const CPU_CHAR *)0) {
1157  return (0); /* If BOTH str ptrs NULL, rtn 0 (see Note #3a1A). */
1158  }
1159  char_2 = ASCII_ToLower(*p2_str);
1160  cmp_val = (CPU_INT16S)0 - (CPU_INT16S)char_2;
1161  return (cmp_val); /* If p1_str NULL, rtn neg p2_str val (see Note #3a1B1).*/
1162  }
1163  if (p2_str == (const CPU_CHAR *)0) {
1164  char_1 = ASCII_ToLower(*p1_str);
1165  cmp_val = (CPU_INT16S)char_1;
1166  return (cmp_val); /* If p2_str NULL, rtn pos p1_str val (see Note #3a1B2).*/
1167  }
1168 
1169 
1170  p1_str_cmp = p1_str;
1171  p2_str_cmp = p2_str;
1172  p1_str_cmp_next = p1_str_cmp;
1173  p2_str_cmp_next = p2_str_cmp;
1174  p1_str_cmp_next++;
1175  p2_str_cmp_next++;
1176  char_1 = ASCII_ToLower(*p1_str_cmp);
1177  char_2 = ASCII_ToLower(*p2_str_cmp);
1178  cmp_len = 0u;
1179 
1180  while (( char_1 == char_2) && /* Cmp strs until non-matching chars (see Note #3c) ... */
1181  (*p1_str_cmp != ( CPU_CHAR )'\0') && /* ... or NULL chars (see Note #3b) ... */
1182  ( p1_str_cmp_next != (const CPU_CHAR *) 0 ) && /* ... or NULL ptr(s) found (see Note #3a2); */
1183  ( p2_str_cmp_next != (const CPU_CHAR *) 0 ) &&
1184  ( cmp_len < ( CPU_SIZE_T)len_max)) { /* ... or max nbr chars cmp'd (see Note #3d2). */
1185  p1_str_cmp++;
1186  p2_str_cmp++;
1187  p1_str_cmp_next++;
1188  p2_str_cmp_next++;
1189  cmp_len++;
1190  char_1 = ASCII_ToLower(*p1_str_cmp);
1191  char_2 = ASCII_ToLower(*p2_str_cmp);
1192  }
1193 
1194 
1195  if (cmp_len == len_max) { /* If strs identical for max len nbr of chars, ... */
1196  return (0); /* ... rtn 0 (see Note #3d2A). */
1197  }
1198 
1199  if (char_1 != char_2) { /* If strs NOT identical, ... */
1200  cmp_val = (CPU_INT16S)char_1 - (CPU_INT16S)char_2; /* ... calc & rtn char diff (see Note #3c1). */
1201 
1202  } else if (char_1 == (CPU_CHAR)'\0') { /* If NULL char(s) found, ... */
1203  cmp_val = (CPU_INT16S)0; /* ... strs identical; rtn 0 (see Note #3b). */
1204 
1205  } else {
1206  if (p1_str_cmp_next == (const CPU_CHAR *)0) {
1207  if (p2_str_cmp_next == (const CPU_CHAR *)0) { /* If BOTH next str ptrs NULL, ... */
1208  cmp_val = (CPU_INT16S)0; /* ... rtn 0 (see Note #3a2A). */
1209  } else { /* If p1_str_cmp_next NULL, ... */
1210  char_2 = ASCII_ToLower(*p2_str_cmp_next);
1211  cmp_val = (CPU_INT16S)0 - (CPU_INT16S)char_2; /* ... rtn neg p2_str_cmp_next val (see Note #3a2B1). */
1212  }
1213  } else { /* If p2_str_cmp_next NULL, ... */
1214  char_1 = ASCII_ToLower(*p1_str_cmp_next);
1215  cmp_val = (CPU_INT16S)char_1; /* ... rtn pos p1_str_cmp_next val (see Note #3a2B2). */
1216  }
1217  }
1218 
1219 
1220  return (cmp_val);
1221 }
1222 
1223 
1224 /*$PAGE*/
1225 /*
1226 *********************************************************************************************************
1227 * Str_Char()
1228 *
1229 * Description : Search string for first occurrence of specific character.
1230 *
1231 * Argument(s) : pstr Pointer to string (see Note #1).
1232 *
1233 * srch_char Search character.
1234 *
1235 * Return(s) : Pointer to first occurrence of search character in string, if any (see Note #2b1).
1236 *
1237 * Pointer to NULL, otherwise (see Note #2b2).
1238 *
1239 * Caller(s) : Application.
1240 *
1241 * Note(s) : (1) String buffer NOT modified.
1242 *
1243 * (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strchr() : DESCRIPTION' states that :
1244 *
1245 * (1) "The strchr() function shall locate the first occurrence of 'c' ('srch_char')
1246 * ... in the string pointed to by 's' ('pstr')."
1247 * (2) "The terminating null byte is considered to be part of the string."
1248 *
1249 * (b) IEEE Std 1003.1, 2004 Edition, Section 'strchr() : RETURN VALUE' states that
1250 * "upon completion, strchr() shall return" :
1251 *
1252 * (1) "a pointer to the byte," ...
1253 * (2) "or a null pointer if the byte was not found."
1254 * (A) #### Although NO strchr() specification states to return NULL for
1255 * any other reason(s), NULL is also returned for any error(s).
1256 *
1257 * (3) String search terminates when :
1258 *
1259 * (a) String pointer passed a NULL pointer.
1260 * (1) No string search performed; NULL pointer returned.
1261 *
1262 * (b) String pointer points to NULL.
1263 * (1) String overlaps with NULL address; NULL pointer returned.
1264 *
1265 * (c) String's terminating NULL character found.
1266 * (1) Search character NOT found in search string; NULL pointer returned
1267 * (see Note #2b2).
1268 * (2) Applicable even if search character is the terminating NULL character
1269 * (see Note #2a2).
1270 *
1271 * (d) Search character found.
1272 * (1) Return pointer to first occurrence of search character in search string
1273 * (see Note #2a1).
1274 *********************************************************************************************************
1275 */
1276 
1278  CPU_CHAR srch_char)
1279 {
1280  CPU_CHAR *pstr_rtn;
1281 
1282 
1283  pstr_rtn = Str_Char_N(pstr,
1284  DEF_INT_CPU_U_MAX_VAL,
1285  srch_char);
1286 
1287  return (pstr_rtn);
1288 }
1289 
1290 
1291 /*$PAGE*/
1292 /*
1293 *********************************************************************************************************
1294 * Str_Char_N()
1295 *
1296 * Description : Search string for first occurrence of specific character, up to a maximum number
1297 * of characters.
1298 *
1299 * Argument(s) : pstr Pointer to string (see Note #1).
1300 *
1301 * len_max Maximum number of characters to search (see Notes #2c & #3e).
1302 *
1303 * srch_char Search character.
1304 *
1305 * Return(s) : Pointer to first occurrence of search character in string, if any (see Note #2b1).
1306 *
1307 * Pointer to NULL, otherwise (see Note #2b2).
1308 *
1309 * Caller(s) : Application.
1310 *
1311 * Note(s) : (1) String buffer NOT modified.
1312 *
1313 * (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strchr() : DESCRIPTION' states that :
1314 *
1315 * (1) "The strchr() function shall locate the first occurrence of 'c' ('srch_char')
1316 * ... in the string pointed to by 's' ('pstr')."
1317 * (2) "The terminating null byte is considered to be part of the string."
1318 *
1319 * (b) IEEE Std 1003.1, 2004 Edition, Section 'strchr() : RETURN VALUE' states that
1320 * "upon completion, strchr() shall return" :
1321 *
1322 * (1) "a pointer to the byte," ...
1323 * (2) "or a null pointer if the byte was not found."
1324 * (A) #### Although NO strchr() specification states to return NULL for
1325 * any other reason(s), NULL is also returned for any error(s).
1326 *
1327 * (c) Ideally, the 'len_max' argument would be the last argument in this function's
1328 * argument list for consistency with all other custom string library functions.
1329 * However, the 'len_max' argument is sequentially ordered as the second argument
1330 * to comply with most standard library's strnchr() argument list.
1331 *
1332 * (3) String search terminates when :
1333 *
1334 * (a) String pointer passed a NULL pointer.
1335 * (1) No string search performed; NULL pointer returned.
1336 *
1337 * (b) String pointer points to NULL.
1338 * (1) String overlaps with NULL address; NULL pointer returned.
1339 *
1340 * (c) String's terminating NULL character found.
1341 * (1) Search character NOT found in search string; NULL pointer returned
1342 * (see Note #2b2).
1343 * (2) Applicable even if search character is the terminating NULL character
1344 * (see Note #2a2).
1345 *
1346 * (d) Search character found.
1347 * (1) Return pointer to first occurrence of search character in search string
1348 * (see Note #2a1).
1349 *
1350 * (e) 'len_max' number of characters searched.
1351 * (1) Search character NOT found in search string within first 'len_max' number
1352 * of characters; NULL pointer returned.
1353 * (2) 'len_max' number of characters MAY include terminating NULL character
1354 * (see Note #2a2).
1355 *********************************************************************************************************
1356 */
1357 /*$PAGE*/
1359  CPU_SIZE_T len_max,
1360  CPU_CHAR srch_char)
1361 {
1362  const CPU_CHAR *pstr_char;
1363  CPU_SIZE_T len_srch;
1364 
1365 
1366  if (pstr == (const CPU_CHAR *)0) { /* Rtn NULL if srch str ptr NULL (see Note #3a1). */
1367  return ((CPU_CHAR *)0);
1368  }
1369 
1370  if (len_max == 0) { /* Rtn NULL if srch len = 0 (see Note #3e1). */
1371  return ((CPU_CHAR *)0);
1372  }
1373 
1374 
1375  pstr_char = pstr;
1376  len_srch = 0u;
1377 
1378  while (( pstr_char != (const CPU_CHAR *) 0 ) && /* Srch str until NULL ptr [see Note #3b] ... */
1379  (*pstr_char != ( CPU_CHAR )'\0') && /* ... or NULL char (see Note #3c) ... */
1380  (*pstr_char != ( CPU_CHAR )srch_char) && /* ... or srch char found (see Note #3d); ... */
1381  ( len_srch < ( CPU_SIZE_T)len_max)) { /* ... or max nbr chars srch'd (see Note #3e). */
1382  pstr_char++;
1383  len_srch++;
1384  }
1385 
1386 
1387  if (pstr_char == (const CPU_CHAR *)0) { /* Rtn NULL if NULL ptr found (see Note #3b1). */
1388  return ((CPU_CHAR *)0);
1389  }
1390 
1391  if (len_srch >= len_max) { /* Rtn NULL if srch char NOT found ... */
1392  return ((CPU_CHAR *)0); /* ... within max nbr of chars (see Note #3e1). */
1393  }
1394 
1395  if (*pstr_char != srch_char) { /* Rtn NULL if srch char NOT found (see Note #3c1). */
1396  return ((CPU_CHAR *)0);
1397  }
1398 
1399 
1400  return ((CPU_CHAR *)pstr_char); /* Else rtn ptr to found srch char (see Note #3d1). */
1401 }
1402 
1403 
1404 /*$PAGE*/
1405 /*
1406 *********************************************************************************************************
1407 * Str_Char_Last()
1408 *
1409 * Description : Search string for last occurrence of specific character.
1410 *
1411 * Argument(s) : pstr Pointer to string (see Note #1).
1412 *
1413 * srch_char Search character.
1414 *
1415 * Return(s) : Pointer to last occurrence of search character in string, if any (see Note #2b1).
1416 *
1417 * Pointer to NULL, otherwise (see Note #2b2).
1418 *
1419 * Caller(s) : Application.
1420 *
1421 * Note(s) : (1) String buffer NOT modified.
1422 *
1423 * (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strrchr() : DESCRIPTION' states that :
1424 *
1425 * (1) "The strrchr() function shall locate the last occurrence of 'c' ('srch_char')
1426 * ... in the string pointed to by 's' ('pstr')."
1427 * (2) "The terminating null byte is considered to be part of the string."
1428 *
1429 * (b) IEEE Std 1003.1, 2004 Edition, Section 'strrchr() : RETURN VALUE' states that
1430 * "upon successful completion, strrchr() shall return" :
1431 *
1432 * (1) "a pointer to the byte" ...
1433 * (2) "or a null pointer if 'c' ('srch_char') does not occur in the string."
1434 * (A) #### Although NO strrchr() specification states to return NULL for
1435 * any other reason(s), NULL is also returned for any error(s).
1436 *
1437 * (3) String search terminates when :
1438 *
1439 * (a) String pointer passed a NULL pointer.
1440 * (1) No string search performed; NULL pointer returned.
1441 *
1442 * (b) String pointer points to NULL.
1443 * (1) String overlaps with NULL address; NULL pointer returned.
1444 *
1445 * (c) String searched from end to beginning.
1446 * (1) Search character NOT found in search string; NULL pointer returned.
1447 * (2) Applicable even if search character is the terminating NULL character
1448 * (see Note #2a2).
1449 *
1450 * (d) Search character found.
1451 * (1) Return pointer to last occurrence of search character in search string
1452 * (see Note #2a1).
1453 *********************************************************************************************************
1454 */
1455 
1457  CPU_CHAR srch_char)
1458 {
1459  CPU_CHAR *pstr_rtn;
1460 
1461 
1462  pstr_rtn = Str_Char_Last_N(pstr,
1463  DEF_INT_CPU_U_MAX_VAL,
1464  srch_char);
1465 
1466  return (pstr_rtn);
1467 }
1468 
1469 
1470 /*$PAGE*/
1471 /*
1472 *********************************************************************************************************
1473 * Str_Char_Last_N()
1474 *
1475 * Description : Search string for last occurrence of specific character, up to a maximum number
1476 * of characters.
1477 *
1478 * Argument(s) : pstr Pointer to string (see Note #1).
1479 *
1480 * len_max Maximum number of characters to search (see Notes #2c & #3e).
1481 *
1482 * srch_char Search character.
1483 *
1484 * Return(s) : Pointer to last occurrence of search character in string, if any (see Note #2b1).
1485 *
1486 * Pointer to NULL, otherwise (see Note #2b2).
1487 *
1488 * Caller(s) : Application.
1489 *
1490 * Note(s) : (1) String buffer NOT modified.
1491 *
1492 * (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strrchr() : DESCRIPTION' states that :
1493 *
1494 * (1) "The strrchr() function shall locate the last occurrence of 'c' ('srch_char')
1495 * ... in the string pointed to by 's' ('pstr')."
1496 * (2) "The terminating null byte is considered to be part of the string."
1497 *
1498 * (b) IEEE Std 1003.1, 2004 Edition, Section 'strrchr() : RETURN VALUE' states that
1499 * "upon successful completion, strrchr() shall return" :
1500 *
1501 * (1) "a pointer to the byte" ...
1502 * (2) "or a null pointer if 'c' ('srch_char') does not occur in the string."
1503 * (A) #### Although NO strrchr() specification states to return NULL for
1504 * any other reason(s), NULL is also returned for any error(s).
1505 *
1506 * (c) Ideally, the 'len_max' argument would be the last argument in this function's
1507 * argument list for consistency with all other custom string library functions.
1508 * However, the 'len_max' argument is sequentially ordered as the second argument
1509 * to comply with most standard library's strnrchr() argument list.
1510 *
1511 * See also 'Str_Char_N() Note #2c'.
1512 *
1513 * (3) String search terminates when :
1514 *
1515 * (a) String pointer passed a NULL pointer.
1516 * (1) No string search performed; NULL pointer returned.
1517 *
1518 * (b) String pointer points to NULL.
1519 * (1) String overlaps with NULL address; NULL pointer returned.
1520 *
1521 * (c) String searched from end to beginning.
1522 * (1) Search character NOT found in search string; NULL pointer returned
1523 * (see Note #2b2).
1524 * (2) Applicable even if search character is the terminating NULL character
1525 * (see Note #2a2).
1526 *
1527 * (d) Search character found.
1528 * (1) Return pointer to last occurrence of search character in search string
1529 * (see Note #2a1).
1530 *
1531 * (e) 'len_max' number of characters searched.
1532 * (1) Search character NOT found in search string within last 'len_max' number
1533 * of characters; NULL pointer returned.
1534 * (2) 'len_max' number of characters MAY include terminating NULL character
1535 * (see Note #2a2).
1536 *********************************************************************************************************
1537 */
1538 /*$PAGE*/
1540  CPU_SIZE_T len_max,
1541  CPU_CHAR srch_char)
1542 {
1543  const CPU_CHAR *pstr_char;
1544  CPU_SIZE_T str_len_max;
1545  CPU_SIZE_T str_len;
1546 
1547 
1548  if (pstr == (const CPU_CHAR *)0) { /* Rtn NULL if srch str ptr NULL (see Note #3a1). */
1549  return ((CPU_CHAR *)0);
1550  }
1551 
1552  if (len_max == 0) { /* Rtn NULL if srch len = 0 (see Note #3e1). */
1553  return ((CPU_CHAR *)0);
1554  }
1555 
1556 
1557  pstr_char = pstr;
1558  str_len_max = len_max - sizeof((CPU_CHAR)'\0'); /* Str len adj'd for NULL char len. */
1559  str_len = Str_Len_N(pstr_char, str_len_max);
1560  pstr_char += str_len;
1561 
1562  if (pstr_char == (const CPU_CHAR *)0) { /* Rtn NULL if NULL ptr found (see Note #3b1). */
1563  return ((CPU_CHAR *)0);
1564  }
1565 
1566  while (( pstr_char != pstr) && /* Srch str from end until begining (see Note #3c) ... */
1567  (*pstr_char != srch_char)) { /* ... until srch char found (see Note #3d). */
1568  pstr_char--;
1569  }
1570 
1571 
1572  if (*pstr_char != srch_char) { /* Rtn NULL if srch char NOT found (see Note #3c1). */
1573  return ((CPU_CHAR *)0);
1574  }
1575 
1576 
1577  return ((CPU_CHAR *)pstr_char); /* Else rtn ptr to found srch char (see Note #3d1). */
1578 }
1579 
1580 
1581 /*$PAGE*/
1582 /*
1583 *********************************************************************************************************
1584 * Str_Str()
1585 *
1586 * Description : Search string for first occurence of a specific search string.
1587 *
1588 * Argument(s) : pstr Pointer to string (see Note #1).
1589 *
1590 * pstr_srch Pointer to search string (see Note #1).
1591 *
1592 * Return(s) : Pointer to first occurrence of search string in string, if any (see Note #2b1A).
1593 *
1594 * Pointer to string, if NULL search string (see Note #2b2).
1595 *
1596 * Pointer to NULL, otherwise (see Note #2b1B).
1597 *
1598 * Caller(s) : Application.
1599 *
1600 * Note(s) : (1) String buffers NOT modified.
1601 *
1602 * (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strstr() : DESCRIPTION' states that :
1603 *
1604 * (1) "The strstr() function shall locate the first occurrence in the string
1605 * pointed to by 's1' ('pstr') of the sequence of bytes ... in the string
1606 * pointed to by 's2' ('pstr_srch')" ...
1607 * (2) "(excluding the terminating null byte)."
1608 *
1609 * (b) IEEE Std 1003.1, 2004 Edition, Section 'strstr() : RETURN VALUE' states that :
1610 *
1611 * (1) "Upon successful completion, strstr() shall return" :
1612 * (A) "a pointer to the located string" ...
1613 * (B) "or a null pointer if the string is not found."
1614 * (1) #### Although NO strstr() specification states to return NULL for
1615 * any other reason(s), NULL is also returned for any error(s).
1616 *
1617 * (2) "If 's2' ('pstr_srch') points to a string with zero length, the function
1618 * shall return 's1' ('pstr')."
1619 *
1620 * (3) String search terminates when :
1621 *
1622 * (a) String pointer(s) are passed NULL pointers.
1623 * (1) No string search performed; NULL pointer returned.
1624 *
1625 * (b) String pointer(s) point to NULL.
1626 * (1) String buffer(s) overlap with NULL address; NULL pointer returned.
1627 *
1628 * (c) Search string length equal to zero.
1629 * (1) No string search performed; string pointer returned (see Note #2b2).
1630 *
1631 * (d) Search string length greater than string length.
1632 * (1) No string search performed; NULL pointer returned (see Note #2b1B).
1633 *
1634 * (e) Entire string has been searched.
1635 * (1) Search string not found; NULL pointer returned (see Note #2b1B).
1636 *
1637 * (f) Search string found.
1638 * (1) Return pointer to first occurrence of search string in string (see Note #2b1A).
1639 *********************************************************************************************************
1640 */
1641 
1642 CPU_CHAR *Str_Str (const CPU_CHAR *pstr,
1643  const CPU_CHAR *pstr_srch)
1644 {
1645  CPU_CHAR *pstr_rtn;
1646 
1647 
1648  pstr_rtn = Str_Str_N(pstr,
1649  pstr_srch,
1650  DEF_INT_CPU_U_MAX_VAL);
1651 
1652  return (pstr_rtn);
1653 }
1654 
1655 
1656 /*$PAGE*/
1657 /*
1658 *********************************************************************************************************
1659 * Str_Str_N()
1660 *
1661 * Description : Search string for first occurence of a specific search string, up to a maximum number
1662 * of characters.
1663 *
1664 * Argument(s) : pstr Pointer to string (see Note #1).
1665 *
1666 * pstr_srch Pointer to search string (see Note #1).
1667 *
1668 * len_max Maximum number of characters to search (see Note #3g).
1669 *
1670 * Return(s) : Pointer to first occurrence of search string in string, if any (see Note #2b1A).
1671 *
1672 * Pointer to string, if NULL search string (see Note #2b2).
1673 *
1674 * Pointer to NULL, otherwise (see Note #2b1B).
1675 *
1676 * Caller(s) : Application.
1677 *
1678 * Note(s) : (1) String buffers NOT modified.
1679 *
1680 * (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strstr() : DESCRIPTION' states that :
1681 *
1682 * (1) "The strstr() function shall locate the first occurrence in the string
1683 * pointed to by 's1' ('pstr') of the sequence of bytes ... in the string
1684 * pointed to by 's2' ('pstr_srch')" ...
1685 * (2) "(excluding the terminating null byte)."
1686 *
1687 * (b) IEEE Std 1003.1, 2004 Edition, Section 'strstr() : RETURN VALUE' states that :
1688 *
1689 * (1) "Upon successful completion, strstr() shall return" :
1690 * (A) "a pointer to the located string" ...
1691 * (B) "or a null pointer if the string is not found."
1692 * (1) #### Although NO strstr() specification states to return NULL for
1693 * any other reason(s), NULL is also returned for any error(s).
1694 *
1695 * (2) "If 's2' ('pstr_srch') points to a string with zero length, the function
1696 * shall return 's1' ('pstr')."
1697 *
1698 * (3) String search terminates when :
1699 *
1700 * (a) String pointer(s) are passed NULL pointers.
1701 * (1) No string search performed; NULL pointer returned.
1702 *
1703 * (b) String pointer(s) point to NULL.
1704 * (1) String buffer(s) overlap with NULL address; NULL pointer returned.
1705 *
1706 * (c) Search string length equal to zero.
1707 * (1) No string search performed; string pointer returned (see Note #2b2).
1708 *
1709 * (d) Search string length greater than string length.
1710 * (1) No string search performed; NULL pointer returned (see Note #2b1B).
1711 *
1712 * (e) Entire string has been searched.
1713 * (1) Search string not found; NULL pointer returned (see Note #2b1B).
1714 * (2) Maximum size of the search is defined as the subtraction of the
1715 * search string length from the string length.
1716 *
1717 * (f) Search string found.
1718 * (1) Return pointer to first occurrence of search string in string (see Note #2b1A).
1719 * (2) Search string found via Str_Cmp_N().
1720 *
1721 * (g) 'len_max' number of characters searched.
1722 * (1) 'len_max' number of characters does NOT include terminating NULL character
1723 * (see Note #2a2).
1724 *********************************************************************************************************
1725 */
1726 /*$PAGE*/
1728  const CPU_CHAR *pstr_srch,
1729  CPU_SIZE_T len_max)
1730 {
1731  CPU_SIZE_T str_len;
1732  CPU_SIZE_T str_len_srch;
1733  CPU_SIZE_T len_max_srch;
1734  CPU_SIZE_T srch_len;
1735  CPU_SIZE_T srch_ix;
1736  CPU_BOOLEAN srch_done;
1737  CPU_INT16S srch_cmp;
1738  const CPU_CHAR *pstr_str;
1739  const CPU_CHAR *pstr_srch_ix;
1740 
1741  /* Rtn NULL if str ptr(s) NULL (see Note #3a). */
1742  if (pstr == (const CPU_CHAR *)0) {
1743  return ((CPU_CHAR *)0);
1744  }
1745  if (pstr_srch == (const CPU_CHAR *)0) {
1746  return ((CPU_CHAR *)0);
1747  }
1748 
1749  if (len_max == 0) { /* Rtn NULL if srch len = 0 (see Note #3g). */
1750  return ((CPU_CHAR *)0);
1751  }
1752 
1753  /* Lim max srch str len (to chk > str len). */
1754  len_max_srch = (len_max < DEF_INT_CPU_U_MAX_VAL)
1755  ? (len_max + 1u) : DEF_INT_CPU_U_MAX_VAL;
1756 
1757  str_len = Str_Len_N(pstr, len_max);
1758  str_len_srch = Str_Len_N(pstr_srch, len_max_srch);
1759  if (str_len_srch == 0) { /* Rtn ptr to str if srch str len = 0 (see Note #2b2). */
1760  return ((CPU_CHAR *)pstr);
1761  }
1762  if (str_len_srch > str_len) { /* Rtn NULL if srch str len > str len (see Note #3d). */
1763  return ((CPU_CHAR *)0);
1764  }
1765  /* Rtn NULL if NULL ptr found (see Note #3b1). */
1766  pstr_str = pstr + str_len;
1767  if (pstr_str == (const CPU_CHAR *)0) {
1768  return ((CPU_CHAR *)0);
1769  }
1770  pstr_str = pstr_srch + str_len_srch;
1771  if (pstr_str == (const CPU_CHAR *)0) {
1772  return ((CPU_CHAR *)0);
1773  }
1774 
1775 
1776  srch_len = str_len - str_len_srch; /* Calc srch len (see Note #3e2). */
1777  srch_ix = 0u;
1778  srch_done = DEF_NO;
1779 
1780  do {
1781  pstr_srch_ix = (const CPU_CHAR *)(pstr + srch_ix);
1782  srch_cmp = Str_Cmp_N(pstr_srch_ix, pstr_srch, str_len_srch);
1783  srch_done = (srch_cmp == 0) ? DEF_YES : DEF_NO;
1784  srch_ix++;
1785  } while ((srch_done == DEF_NO) && (srch_ix <= srch_len));
1786 
1787 
1788  if (srch_cmp != 0) { /* Rtn NULL if srch str NOT found (see Note #3e2). */
1789  return ((CPU_CHAR *)0);
1790  }
1791 
1792  return ((CPU_CHAR *)pstr_srch_ix); /* Else rtn ptr to found srch str (see Note #3f1). */
1793 }
1794 
1795 
1796 /*$PAGE*/
1797 /*
1798 *********************************************************************************************************
1799 * Str_FmtNbr_Int32U()
1800 *
1801 * Description : Format 32-bit unsigned integer into a multi-digit character string.
1802 *
1803 * Argument(s) : nbr Number to format.
1804 *
1805 * nbr_dig Number of digits to format (see Note #1).
1806 *
1807 * The following may be used to specify the number of digits to format :
1808 *
1809 * DEF_INT_32U_NBR_DIG_MIN Minimum number of 32-bit unsigned digits
1810 * DEF_INT_32U_NBR_DIG_MAX Maximum number of 32-bit unsigned digits
1811 *
1812 * nbr_base Base of number to format (see Note #2).
1813 *
1814 * The following may be used to specify the number base :
1815 *
1816 * DEF_NBR_BASE_BIN Base 2
1817 * DEF_NBR_BASE_OCT Base 8
1818 * DEF_NBR_BASE_DEC Base 10
1819 * DEF_NBR_BASE_HEX Base 16
1820 *
1821 * lead_char Prepend leading character (see Note #3) :
1822 *
1823 * '\0' Do NOT prepend leading character to string.
1824 * Printable character Prepend leading character to string.
1825 * Unprintable character Format invalid string (see Note #6).
1826 *
1827 * lower_case Format alphabetic characters (if any) in lower case :
1828 *
1829 * DEF_NO Format alphabetic characters in upper case.
1830 * DEF_YES Format alphabetic characters in lower case.
1831 *
1832 * nul Append terminating NULL-character (see Note #4) :
1833 *
1834 * DEF_NO Do NOT append terminating NULL-character to string.
1835 * DEF_YES Append terminating NULL-character to string.
1836 *
1837 * pstr Pointer to character array to return formatted number string (see Note #5).
1838 *
1839 * Return(s) : Pointer to formatted string, if NO error(s).
1840 *
1841 * Pointer to NULL, otherwise.
1842 *
1843 * Caller(s) : Application.
1844 *
1845 * Note(s) : (1) (a) If the number of digits to format ('nbr_dig') is zero; then NO formatting
1846 * is performed except possible NULL-termination of the string (see Note #4).
1847 *
1848 * Example :
1849 *
1850 * nbr = 23456
1851 * nbr_dig = 0
1852 * nbr_base = 10
1853 *
1854 * pstr = "" See Note #6a
1855 *
1856 * (b) If the number of digits to format ('nbr_dig') is less than the number of
1857 * significant integer digits of the number to format ('nbr'); then an invalid
1858 * string is formatted instead of truncating any significant integer digits.
1859 *
1860 * Example :
1861 *
1862 * nbr = 23456
1863 * nbr_dig = 3
1864 * nbr_base = 10
1865 *
1866 * pstr = "???" See Note #6b
1867 *
1868 * (2) The number's base MUST be between 2 & 36, inclusive.
1869 *$PAGE*
1870 * (3) Leading character option prepends leading characters prior to the first non-zero digit.
1871 *
1872 * (a) (1) Leading character MUST be a printable ASCII character.
1873 *
1874 * (2) (A) Leading character MUST NOT be a number base digit, ...
1875 * (B) with the exception of '0'.
1876 *
1877 * (b) The number of leading characters is such that the total number of significant
1878 * integer digits plus the number of leading characters is equal to the requested
1879 * number of integer digits to format ('nbr_dig').
1880 *
1881 * Example :
1882 *
1883 * nbr = 23456
1884 * nbr_dig = 7
1885 * nbr_base = 10
1886 * lead_char = ' '
1887 *
1888 * pstr = " 23456"
1889 *
1890 * (c) (1) If the value of the number to format is zero ...
1891 * (2) ... & the number of digits to format is non-zero, ...
1892 * (3) ... but NO leading character available; ...
1893 * (4) ... then one digit of '0' value is formatted.
1894 *
1895 * This is NOT a leading character; but a single integer digit of '0' value.
1896 *
1897 * (4) (a) NULL-character terminate option DISABLED prevents overwriting previous character
1898 * array formatting.
1899 *
1900 * (b) WARNING: Unless 'pstr' character array is pre-/post-terminated, NULL-character
1901 * terminate option DISABLED will cause character string run-on.
1902 *
1903 * (5) (a) Format buffer size NOT validated; buffer overruns MUST be prevented by caller.
1904 *
1905 * (b) To prevent character buffer overrun :
1906 *
1907 * Character array size MUST be >= ('nbr_dig' +
1908 * 1 'NUL' terminator) characters
1909 *
1910 * (6) For any unsuccessful string format or error(s), an invalid string of question marks
1911 * ('?') will be formatted, where the number of question marks is determined by the
1912 * number of digits to format ('nbr_dig') :
1913 *
1914 * Invalid string's { (a) 0 (NULL string) , if 'nbr_dig' = 0
1915 * number of = {
1916 * question marks { (b) 'nbr_dig' , if 'nbr_dig' > 0
1917 *
1918 *********************************************************************************************************
1919 */
1920 
1922  CPU_INT08U nbr_dig,
1923  CPU_INT08U nbr_base,
1924  CPU_CHAR lead_char,
1925  CPU_BOOLEAN lower_case,
1926  CPU_BOOLEAN nul,
1927  CPU_CHAR *pstr)
1928 {
1929  CPU_CHAR *pstr_fmt;
1930 
1931 
1932  pstr_fmt = Str_FmtNbr_Int32(nbr, /* Fmt unsigned int into str. */
1933  nbr_dig,
1934  nbr_base,
1935  DEF_NO,
1936  lead_char,
1937  lower_case,
1938  nul,
1939  pstr);
1940 
1941  return (pstr_fmt);
1942 }
1943 
1944 
1945 /*$PAGE*/
1946 /*
1947 *********************************************************************************************************
1948 * Str_FmtNbr_Int32S()
1949 *
1950 * Description : Format 32-bit signed integer into a multi-digit character string.
1951 *
1952 * Argument(s) : nbr Number to format.
1953 *
1954 * nbr_dig Number of digits to format (see Note #1).
1955 *
1956 * The following may be used to specify the number of digits to format :
1957 *
1958 * DEF_INT_32S_NBR_DIG_MIN + 1 Minimum number of 32-bit signed digits
1959 * DEF_INT_32S_NBR_DIG_MAX + 1 Maximum number of 32-bit signed digits
1960 * (plus 1 digit for possible negative sign)
1961 *
1962 * nbr_base Base of number to format (see Note #2).
1963 *
1964 * The following may be used to specify the number base :
1965 *
1966 * DEF_NBR_BASE_BIN Base 2
1967 * DEF_NBR_BASE_OCT Base 8
1968 * DEF_NBR_BASE_DEC Base 10
1969 * DEF_NBR_BASE_HEX Base 16
1970 *
1971 * lead_char Prepend leading character (see Note #3) :
1972 *
1973 * '\0' Do NOT prepend leading character to string.
1974 * Printable character Prepend leading character to string.
1975 * Unprintable character Format invalid string (see Note #6).
1976 *
1977 * lower_case Format alphabetic characters (if any) in lower case :
1978 *
1979 * DEF_NO Format alphabetic characters in upper case.
1980 * DEF_YES Format alphabetic characters in lower case.
1981 *
1982 * nul Append terminating NULL-character (see Note #4) :
1983 *
1984 * DEF_NO Do NOT append terminating NULL-character to string.
1985 * DEF_YES Append terminating NULL-character to string.
1986 *
1987 * pstr Pointer to character array to return formatted number string (see Note #5).
1988 *
1989 * Return(s) : Pointer to formatted string, if NO error(s).
1990 *
1991 * Pointer to NULL, otherwise.
1992 *
1993 * Caller(s) : Application.
1994 *
1995 * Note(s) : (1) (a) If the number of digits to format ('nbr_dig') is zero; then NO formatting
1996 * is performed except possible NULL-termination of the string (see Note #4).
1997 *
1998 * Example :
1999 *
2000 * nbr = -23456
2001 * nbr_dig = 0
2002 * nbr_base = 10
2003 *
2004 * pstr = "" See Note #6a
2005 *
2006 * (b) If the number of digits to format ('nbr_dig') is less than the number of
2007 * significant integer digits of the number to format ('nbr'); then an invalid
2008 * string is formatted instead of truncating any significant integer digits.
2009 *
2010 * Example :
2011 *
2012 * nbr = 23456
2013 * nbr_dig = 3
2014 * nbr_base = 10
2015 *
2016 * pstr = "???" See Note #6b
2017 *
2018 * (c) If the number to format ('nbr') is negative but the number of digits to format
2019 * ('nbr_dig') is equal to the number of significant integer digits of the number
2020 * to format ('nbr'); then an invalid string is formatted instead of truncating
2021 * the negative sign.
2022 *
2023 * Example :
2024 *
2025 * nbr = -23456
2026 * nbr_dig = 5
2027 * nbr_base = 10
2028 *
2029 * pstr = "?????" See Note #6b
2030 *
2031 * (2) The number's base MUST be between 2 & 36, inclusive.
2032 *$PAGE*
2033 * (3) Leading character option prepends leading characters prior to the first non-zero digit.
2034 *
2035 * (a) (1) Leading character MUST be a printable ASCII character.
2036 *
2037 * (2) (A) Leading character MUST NOT be a number base digit, ...
2038 * (B) with the exception of '0'.
2039 *
2040 * (b) (1) The number of leading characters is such that the total number of significant
2041 * integer digits plus the number of leading characters plus possible negative
2042 * sign character is equal to the requested number of integer digits to format
2043 * ('nbr_dig').
2044 *
2045 * Examples :
2046 *
2047 * nbr = 23456
2048 * nbr_dig = 7
2049 * nbr_base = 10
2050 * lead_char = ' '
2051 *
2052 * pstr = " 23456"
2053 *
2054 *
2055 * nbr = -23456
2056 * nbr_dig = 7
2057 * nbr_base = 10
2058 * lead_char = ' '
2059 *
2060 * pstr = " -23456"
2061 *
2062 * (2) (A) If the number to format ('nbr') is negative AND the leading character
2063 * ('lead_char') is a '0' digit; then the negative sign character
2064 * prefixes all leading characters prior to the formatted number.
2065 *
2066 * Examples :
2067 *
2068 * nbr = -23456
2069 * nbr_dig = 8
2070 * nbr_base = 10
2071 * lead_char = '0'
2072 *
2073 * pstr = "-0023456"
2074 *
2075 *
2076 * nbr = -43981
2077 * nbr_dig = 8
2078 * nbr_base = 16
2079 * lead_char = '0'
2080 * lower_case = DEF_NO
2081 *
2082 * pstr = "-000ABCD"
2083 *
2084 * (B) If the number to format ('nbr') is negative AND the leading character
2085 * ('lead_char') is NOT a '0' digit; then the negative sign character
2086 * immediately prefixes the most significant digit of the formatted number.
2087 *
2088 * Examples :
2089 *
2090 * nbr = -23456
2091 * nbr_dig = 8
2092 * nbr_base = 10
2093 * lead_char = '#'
2094 *
2095 * pstr = "##-23456"
2096 *
2097 *
2098 * nbr = -43981
2099 * nbr_dig = 8
2100 * nbr_base = 16
2101 * lead_char = '#'
2102 * lower_case = DEF_YES
2103 *
2104 * pstr = "###-abcd"
2105 *
2106 * (c) (1) If the value of the number to format is zero ...
2107 * (2) ... & the number of digits to format is non-zero, ...
2108 * (3) ... but NO leading character available; ...
2109 * (4) ... then one digit of '0' value is formatted.
2110 *
2111 * This is NOT a leading character; but a single integer digit of '0' value.
2112 *$PAGE*
2113 * (4) (a) NULL-character terminate option DISABLED prevents overwriting previous character
2114 * array formatting.
2115 *
2116 * (b) WARNING: Unless 'pstr' character array is pre-/post-terminated, NULL-character
2117 * terminate option DISABLED will cause character string run-on.
2118 *
2119 * (5) (a) Format buffer size NOT validated; buffer overruns MUST be prevented by caller.
2120 *
2121 * (b) To prevent character buffer overrun :
2122 *
2123 * Character array size MUST be >= ('nbr_dig' +
2124 * 1 negative sign +
2125 * 1 'NUL' terminator) characters
2126 *
2127 * (6) For any unsuccessful string format or error(s), an invalid string of question marks
2128 * ('?') will be formatted, where the number of question marks is determined by the
2129 * number of digits to format ('nbr_dig') :
2130 *
2131 * Invalid string's { (a) 0 (NULL string) , if 'nbr_dig' = 0
2132 * number of = {
2133 * question marks { (b) 'nbr_dig' , if 'nbr_dig' > 0
2134 *
2135 *********************************************************************************************************
2136 */
2137 
2139  CPU_INT08U nbr_dig,
2140  CPU_INT08U nbr_base,
2141  CPU_CHAR lead_char,
2142  CPU_BOOLEAN lower_case,
2143  CPU_BOOLEAN nul,
2144  CPU_CHAR *pstr)
2145 {
2146  CPU_CHAR *pstr_fmt;
2147  CPU_INT32S nbr_fmt;
2148  CPU_BOOLEAN nbr_neg;
2149 
2150 
2151  if (nbr < 0) { /* If nbr neg, ... */
2152  nbr_fmt = -nbr; /* ... negate nbr. */
2153  nbr_neg = DEF_YES;
2154  } else {
2155  nbr_fmt = nbr;
2156  nbr_neg = DEF_NO;
2157  }
2158 
2159  pstr_fmt = Str_FmtNbr_Int32((CPU_INT32U)nbr_fmt, /* Fmt signed int into str. */
2160  nbr_dig,
2161  nbr_base,
2162  nbr_neg,
2163  lead_char,
2164  lower_case,
2165  nul,
2166  pstr);
2167 
2168  return (pstr_fmt);
2169 }
2170 
2171 
2172 /*$PAGE*/
2173 /*
2174 *********************************************************************************************************
2175 * Str_FmtNbr_32()
2176 *
2177 * Description : Format number into a multi-digit character string.
2178 *
2179 * Argument(s) : nbr Number to format (see Note #1).
2180 *
2181 * nbr_dig Number of decimal digits to format (see Note #2).
2182 *
2183 * nbr_dp Number of decimal point digits to format.
2184 *
2185 * lead_char Prepend leading character (see Note #3) :
2186 *
2187 * '\0' Do NOT prepend leading character to string.
2188 * Printable character Prepend leading character to string.
2189 * Unprintable character Format invalid string (see Note #6d).
2190 *
2191 * nul Append terminating NULL-character (see Note #4) :
2192 *
2193 * DEF_NO Do NOT append terminating NULL-character to string.
2194 * DEF_YES Append terminating NULL-character to string.
2195 *
2196 * pstr Pointer to character array to return formatted number string (see Note #5).
2197 *
2198 * Return(s) : Pointer to formatted string, if NO error(s) [see Note #6c].
2199 *
2200 * Pointer to NULL, otherwise.
2201 *
2202 * Caller(s) : Application.
2203 *
2204 * Note(s) : (1) (a) The maximum accuracy for 32-bit floating-point numbers :
2205 *
2206 *
2207 * Maximum Accuracy log [Internal-Base ^ (Number-Internal-Base-Digits)]
2208 * 32-bit Floating-point Number = -----------------------------------------------------
2209 * log [External-Base]
2210 *
2211 * log [2 ^ 24]
2212 * = --------------
2213 * log [10]
2214 *
2215 * < 7.225 Base-10 Digits
2216 *
2217 * where
2218 * Internal-Base Internal number base of floating-
2219 * point numbers (i.e. 2)
2220 * External-Base External number base of floating-
2221 * point numbers (i.e. 10)
2222 * Number-Internal-Base-Digits Number of internal number base
2223 * significant digits (i.e. 24)
2224 *
2225 * (b) Some CPUs' &/or compilers' floating-point implementations MAY further reduce the
2226 * maximum accuracy.
2227 *$PAGE*
2228 * (2) (a) If the total number of digits to format ('nbr_dig + nbr_dp') is zero; then NO
2229 * formatting is performed except possible NULL-termination of the string (see Note #4).
2230 *
2231 * Example :
2232 *
2233 * nbr = -23456.789
2234 * nbr_dig = 0
2235 * nbr_dp = 0
2236 *
2237 * pstr = "" See Note #7a
2238 *
2239 * (b) (1) If the number of digits to format ('nbr_dig') is less than the number of
2240 * significant integer digits of the number to format ('nbr'); then an invalid
2241 * string is formatted instead of truncating any significant integer digits.
2242 *
2243 * Example :
2244 *
2245 * nbr = 23456.789
2246 * nbr_dig = 3
2247 * nbr_dp = 2
2248 *
2249 * pstr = "??????" See Note #7d
2250 *
2251 * (2) If the number to format ('nbr') is negative but the number of digits to format
2252 * ('nbr_dig') is equal to the number of significant integer digits of the number
2253 * to format ('nbr'); then an invalid string is formatted instead of truncating
2254 * the negative sign.
2255 *
2256 * Example :
2257 *
2258 * nbr = -23456.789
2259 * nbr_dig = 5
2260 * nbr_dp = 2
2261 *
2262 * pstr = "????????" See Note #7d
2263 *
2264 * (3) If the number to format ('nbr') is negative but the number of significant
2265 * integer digits is zero, & the number of digits to format ('nbr_dig') is one
2266 * but the number of decimal point digits to format ('nbr_dp') is zero; then
2267 * an invalid string is formatted instead of truncating the negative sign.
2268 *
2269 * Example :
2270 *
2271 * nbr = -0.7895
2272 * nbr_dig = 1
2273 * nbr_dp = 0
2274 *
2275 * pstr = "?" See Note #7d
2276 *
2277 * (4) (A) If the number to format ('nbr') is negative but the number of significant
2278 * integer digits is zero, & the number of digits to format ('nbr_dig') is
2279 * zero but the number of decimal point digits to format ('nbr_dp') is non-
2280 * zero; then the negative sign immediately prefixes the decimal point --
2281 * with NO decimal digits formatted, NOT even a single decimal digit of '0'.
2282 *
2283 * Example :
2284 *
2285 * nbr = -0.7895
2286 * nbr_dig = 0
2287 * nbr_dp = 2
2288 *
2289 * pstr = "-.78"
2290 *
2291 * (B) If the number to format ('nbr') is positive but the number of significant
2292 * integer digits is zero, & the number of digits to format ('nbr_dig') is
2293 * zero but the number of decimal point digits to format ('nbr_dp') is non-
2294 * zero; then a single decimal digit of '0' prefixes the decimal point.
2295 *
2296 * This '0' digit is used whenever a negative sign is not formatted (see
2297 * Note #2b4A) so that the formatted string's decimal point is not floating,
2298 * but fixed in the string as the 2nd character.
2299 *
2300 * Example :
2301 *
2302 * nbr = 0.7895
2303 * nbr_dig = 0
2304 * nbr_dp = 2
2305 *
2306 * pstr = "0.78"
2307 *$PAGE*
2308 * (c) (1) If the total number of digits to format ('nbr_dig + nbr_dp') is greater than ... :
2309 *
2310 * (A) ... the maximum accuracy of the CPU's &/or compiler's 32-bit floating-point
2311 * numbers, digits following all significantly-accurate digits of the number to
2312 * format ('nbr') will be inaccurate; ...
2313 * (B) ... the configured maximum accuracy ('LIB_STR_CFG_FP_MAX_NBR_DIG_SIG'), all
2314 * digits or decimal places following all significantly-accurate digits of the
2315 * number to format ('nbr') will be replaced & formatted with zeros ('0').
2316 *
2317 * Example :
2318 *
2319 * nbr = 123456789.012345
2320 * nbr_dig = 9
2321 * nbr_dp = 6
2322 * LIB_STR_CFG_FP_MAX_NBR_DIG_SIG = 7
2323 *
2324 * pstr = "123456700.000000"
2325 *
2326 * (2) Therefore, one or more least-significant digit(s) of the number to format ('nbr')
2327 * MAY be rounded & not necessarily truncated due to the inaccuracy of the CPU's
2328 * &/or compiler's floating-point implementation.
2329 *
2330 * See also Note #1.
2331 *
2332 * (3) Leading character option prepends leading characters prior to the first non-zero digit.
2333 *
2334 * (a) (1) Leading character MUST be a printable ASCII character.
2335 *
2336 * (2) (A) Leading character MUST NOT be a base-10 digit, ...
2337 * (B) with the exception of '0'.
2338 *
2339 * (b) (1) The number of leading characters is such that the total number of significant
2340 * integer digits plus the number of leading characters plus possible negative
2341 * sign character is equal to the requested number of integer digits to format
2342 * ('nbr_dig').
2343 *
2344 * Examples :
2345 *
2346 * nbr = 23456.789
2347 * nbr_dig = 7
2348 * nbr_dp = 2
2349 * lead_char = ' '
2350 *
2351 * pstr = " 23456.78"
2352 *
2353 *
2354 * nbr = -23456.789
2355 * nbr_dig = 7
2356 * nbr_dp = 2
2357 * lead_char = ' '
2358 *
2359 * pstr = " -23456.78"
2360 *
2361 * (2) (A) If the number to format ('nbr') is negative AND the leading character
2362 * ('lead_char') is a '0' digit; then the negative sign character
2363 * prefixes all leading characters prior to the formatted number.
2364 *
2365 * Example :
2366 *
2367 * nbr = -23456.789
2368 * nbr_dig = 8
2369 * nbr_dp = 2
2370 * lead_char = '0'
2371 *
2372 * pstr = "-0023456.78"
2373 *
2374 * (B) If the number to format ('nbr') is negative AND the leading character
2375 * ('lead_char') is NOT a '0' digit; then the negative sign character
2376 * immediately prefixes the most significant digit of the formatted number.
2377 *
2378 * Examples :
2379 *
2380 * nbr = -23456.789
2381 * nbr_dig = 8
2382 * nbr_dp = 2
2383 * lead_char = '#'
2384 *
2385 * pstr = "##-23456.78"
2386 *
2387 * (c) (1) If the integer value of the number to format is zero & ...
2388 * (2) ... the number of digits to format is greater than one ...
2389 * (3) ... OR the number is NOT negative, ...
2390 * (4) ... but NO leading character available; ...
2391 * (5) ... then one digit of '0' value is formatted.
2392 *
2393 * This is NOT a leading character; but a single integer digit of '0' value.
2394 *
2395 * See also Note #2b4B.
2396 *$PAGE*
2397 * (4) (a) NULL-character terminate option DISABLED prevents overwriting previous character
2398 * array formatting.
2399 *
2400 * (b) WARNING: Unless 'pstr' character array is pre-/post-terminated, NULL-character
2401 * terminate option DISABLED will cause character string run-on.
2402 *
2403 * (5) (a) Format buffer size NOT validated; buffer overruns MUST be prevented by caller.
2404 *
2405 * (b) To prevent character buffer overrun :
2406 *
2407 * Character array size MUST be >= ('nbr_dig' +
2408 * 'nbr_dp' +
2409 * 1 negative sign +
2410 * 1 decimal point +
2411 * 1 'NUL' terminator) characters
2412 *
2413 * (6) String format terminates when :
2414 *
2415 * (a) Format string pointer is passed a NULL pointer.
2416 * (1) No string formatted; NULL pointer returned.
2417 *
2418 * (b) Total number of digits to format ('nbr_dig + nbr_dp') is zero.
2419 * (1) NULL string formatted (see Note #7a); NULL pointer returned.
2420 *
2421 * (c) Number of digits to format ('nbr_dig') is less than number of significant
2422 * integer digits of the number to format ('nbr'), including possible
2423 * negative sign.
2424 * (1) Invalid string formatted (see Note #7); NULL pointer returned.
2425 *
2426 * (d) Lead character is NOT a valid, printable character (see Note #3a).
2427 * (1) Invalid string formatted (see Note #7); NULL pointer returned.
2428 *
2429 * (e) Number successfully formatted into character string array.
2430 *
2431 * (7) For any unsuccessful string format or error(s), an invalid string of question marks
2432 * ('?') will be formatted, where the number of question marks is determined by the
2433 * number of digits ('nbr_dig') & number of decimal point digits ('nbr_dp') to format :
2434 *
2435 * { (a) 0 (NULL string) , if 'nbr_dig' = 0 AND
2436 * { 'nbr_dp' = 0
2437 * {
2438 * { (b) 'nbr_dig' , if 'nbr_dig' > 0 AND
2439 * { 'nbr_dp' = 0
2440 * Invalid string's {
2441 * number of = { (c) ['nbr_dp' + , if 'nbr_dig' = 0 AND
2442 * question marks { 1 (for decimal point) + 'nbr_dp' > 0
2443 * { 1 (for negative sign) ]
2444 * {
2445 * { (d) ['nbr_dig' + , if 'nbr_dig' > 0 AND
2446 * { 'nbr_dp' + 'nbr_dp' > 0
2447 * { 1 (for decimal point) ]
2448 *
2449 *********************************************************************************************************
2450 */
2451 
2452 #if (LIB_STR_CFG_FP_EN == DEF_ENABLED)
2454  CPU_INT08U nbr_dig,
2455  CPU_INT08U nbr_dp,
2456  CPU_CHAR lead_char,
2457  CPU_BOOLEAN nul,
2458  CPU_CHAR *pstr)
2459 {
2460  CPU_CHAR *pstr_fmt;
2461  CPU_FP32 nbr_fmt;
2462  CPU_FP32 nbr_log;
2463  CPU_INT32U nbr_shiftd;
2464  CPU_INT16U nbr_dig_max;
2465  CPU_INT16U nbr_dig_sig;
2466  CPU_INT08U nbr_neg_sign;
2467  CPU_INT08U dig_val;
2468  CPU_FP32 dig_exp;
2469  CPU_FP32 dp_exp;
2470  CPU_INT08U i;
2471  CPU_BOOLEAN lead_char_dig;
2472  CPU_BOOLEAN lead_char_fmtd;
2473  CPU_BOOLEAN lead_char_0;
2474  CPU_BOOLEAN fmt_invalid;
2475  CPU_BOOLEAN print_char;
2476  CPU_BOOLEAN nbr_neg;
2477  CPU_BOOLEAN nbr_neg_fmtd;
2478 
2479 
2480 /*$PAGE*/
2481  /* ---------------- VALIDATE FMT ARGS ----------------- */
2482  if (pstr == (CPU_CHAR *)0) { /* Rtn NULL if str ptr NULL (see Note #6a). */
2483  return ((CPU_CHAR *)0);
2484  }
2485 
2486  fmt_invalid = DEF_NO;
2487 
2488  if ((nbr_dig < 1) && (nbr_dp < 1)) { /* If nbr digs/dps = 0, ... */
2489  fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6b). */
2490  }
2491 
2492  if (lead_char != (CPU_CHAR)'\0') {
2493  print_char = ASCII_IsPrint(lead_char);
2494  if (print_char != DEF_YES) { /* If lead char non-printable (see Note #3a1), ... */
2495  fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6d). */
2496 
2497  } else if (lead_char != '0') { /* Chk lead char for non-0 dig. */
2498  lead_char_dig = ASCII_IsDig(lead_char);
2499  if (lead_char_dig == DEF_YES) { /* If lead char non-0 dig (see Note #3a2A), ... */
2500  fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6d). */
2501  }
2502  }
2503  }
2504 
2505 
2506  /* ----------------- PREPARE NBR FMT ------------------ */
2507  pstr_fmt = pstr;
2508 
2509  if (fmt_invalid == DEF_NO) {
2510  if (nbr < 0.0f) { /* If nbr neg, ... */
2511  nbr_fmt = -nbr; /* ... negate nbr. */
2512  nbr_neg_sign = 1u;
2513  nbr_neg = DEF_YES;
2514  } else {
2515  nbr_fmt = nbr;
2516  nbr_neg_sign = 0u;
2517  nbr_neg = DEF_NO;
2518  }
2519 
2520  nbr_log = nbr_fmt;
2521  nbr_dig_max = 0u;
2522  while (nbr_log >= 1.0f) { /* While base-10 digs avail, ... */
2523  nbr_dig_max++; /* ... calc max nbr digs. */
2524  nbr_log /= 10.0f;
2525  }
2526 
2527  if (((nbr_dig >= (nbr_dig_max + nbr_neg_sign)) || /* If req'd nbr digs >= (max nbr digs + neg sign) .. */
2528  (nbr_dig_max < 1)) && /* .. or NO nbr digs, .. */
2529  ((nbr_dig > 1) || /* .. but NOT [(req'd nbr dig = 1) AND .. */
2530  (nbr_dp > 0) || /* .. (req'd nbr dp = 0) AND .. */
2531  (nbr_neg == DEF_NO))) { /* .. ( nbr neg )] (see Note #2b3); */
2532  /* .. prepare nbr digs to fmt. */
2533  dig_exp = 1.0f;
2534  for (i = 1u; i < nbr_dig; i++) {
2535  dig_exp *= 10.0f;
2536  }
2537 
2538  nbr_neg_fmtd = DEF_NO;
2539  nbr_dig_sig = 0u;
2540  lead_char_fmtd = DEF_NO;
2541  lead_char_0 = (lead_char == '0') /* Chk if lead char a '0' dig (see Note #3b2). */
2542  ? DEF_YES : DEF_NO;
2543 
2544  } else { /* Else if nbr trunc'd, ... */
2545  fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6c). */
2546  }
2547  }
2548 
2549 
2550 /*$PAGE*/
2551  /* ------------------- FMT NBR STR -------------------- */
2552  for (i = nbr_dig; i > 0; i--) { /* Fmt str for desired nbr digs : */
2553  if (fmt_invalid == DEF_NO) {
2554  if (nbr_dig_sig < LIB_STR_CFG_FP_MAX_NBR_DIG_SIG) { /* If nbr sig digs < max, fmt str digs; ... */
2555  nbr_shiftd = (CPU_INT32U)(nbr_fmt / dig_exp);
2556  if ((nbr_shiftd > 0) || /* If shifted nbr > 0 ... */
2557  (i == 1)) { /* ... OR on one's dig to fmt (see Note #3c1), ... */
2558  /* ... calc & fmt dig val; ... */
2559  if ((nbr_neg == DEF_YES) && /* If nbr neg ... */
2560  (nbr_neg_fmtd == DEF_NO )) { /* ... but neg sign NOT yet fmt'd; ... */
2561 
2562  if (lead_char_fmtd == DEF_YES) { /* ... & if lead char(s) fmt'd, ... */
2563  pstr_fmt--; /* ... replace last lead char w/ ... */
2564  }
2565  *pstr_fmt++ = '-'; /* ... prepend neg sign (see Notes #2b & #3b). */
2566  nbr_neg_fmtd = DEF_YES;
2567  }
2568 
2569  if (nbr_shiftd > 0) { /* If shifted nbr > 0, ... */
2570  dig_val = (CPU_INT08U)(nbr_shiftd % 10u);
2571  *pstr_fmt++ = (CPU_CHAR )(dig_val + '0');
2572 
2573  nbr_dig_sig++; /* ... inc nbr sig digs; ... */
2574 
2575  } else if ((nbr_dig > 1) || /* ... else if req'd digs > 1 ... */
2576  (nbr_neg == DEF_NO)) { /* ... or non-neg nbr, ... */
2577  *pstr_fmt++ = '0'; /* ... fmt one '0' char (see Note #3c5). */
2578  }
2579 
2580  } else if ((nbr_neg == DEF_YES) && /* ... else if nbr neg ... */
2581  (lead_char_0 == DEF_YES) && /* ... & lead char a '0' dig ... */
2582  (nbr_neg_fmtd == DEF_NO )) { /* ... but neg sign NOT yet fmt'd, ... */
2583 
2584  *pstr_fmt++ = '-'; /* ... prepend neg sign (see Note #3b); ... */
2585  nbr_neg_fmtd = DEF_YES;
2586 
2587  } else if (lead_char != (CPU_CHAR)'\0') { /* ... else if avail, ... */
2588  *pstr_fmt++ = lead_char; /* ... fmt lead char. */
2589  lead_char_fmtd = DEF_YES;
2590  }
2591 
2592  dig_exp /= 10.0f; /* Shift to next least-sig dig. */
2593 
2594  } else { /* ... else append non-sig 0's (see Note #2c2). */
2595  *pstr_fmt++ = '0';
2596  }
2597 
2598  } else { /* Else fmt '?' for invalid str (see Note #7). */
2599  *pstr_fmt++ = '?';
2600  }
2601  }
2602 
2603 
2604 /*$PAGE*/
2605  if (nbr_dp > 0) { /* Fmt str for desired nbr dp : */
2606  if (nbr_dig < 1) { /* If NO digs fmt'd; ... */
2607  if (fmt_invalid == DEF_NO) { /* ... nbr fmt valid, ... */
2608  if ((nbr_neg == DEF_YES) && /* ... nbr neg ... */
2609  (nbr_neg_fmtd == DEF_NO )) { /* ... but neg sign NOT yet fmt'd, ... */
2610  *pstr_fmt++ = '-'; /* ... prepend neg sign (see Notes #2b & #3b); ... */
2611  } else { /* ... else prepend 1 dig of '0' (see Note #3c5) ... */
2612  *pstr_fmt++ = '0';
2613  }
2614  } else { /* ... else fmt '?' for invalid str (see Note #7). */
2615  *pstr_fmt++ = '?';
2616  }
2617  }
2618 
2619  if (fmt_invalid == DEF_NO) { /* If nbr fmt valid, ... */
2620  *pstr_fmt++ = '.'; /* ... append dp prior to dp conversion. */
2621  } else { /* Else fmt '?' for invalid str (see Note #7). */
2622  *pstr_fmt++ = '?';
2623  }
2624 
2625  dp_exp = 10.0f;
2626  for (i = 0u; i < nbr_dp; i++) {
2627  if (fmt_invalid == DEF_NO) {
2628  /* If nbr sig digs < max, fmt str dps; ... */
2629  if (nbr_dig_sig < LIB_STR_CFG_FP_MAX_NBR_DIG_SIG) {
2630  nbr_shiftd = (CPU_INT32U)(nbr_fmt * dp_exp);
2631  dig_val = (CPU_INT32U)(nbr_shiftd % 10u);
2632  *pstr_fmt++ = (CPU_CHAR )(dig_val + '0');
2633  dp_exp *= 10.0f; /* Shift to next least-sig dp. */
2634 
2635  if ((nbr_shiftd > 0) || /* If shifted nbr > 0 ... */
2636  (nbr_dig_sig > 0)) { /* ... OR > 0 sig digs already fmt'd, ... */
2637  nbr_dig_sig++; /* ... inc nbr sig digs. */
2638  }
2639 
2640  } else { /* ... else append non-sig 0's (see Note #2c2). */
2641  *pstr_fmt++ = '0';
2642  }
2643 
2644  } else { /* Else fmt '?' for invalid str (see Note #7). */
2645  *pstr_fmt++ = '?';
2646  }
2647  }
2648  }
2649 
2650 
2651  if (nul != DEF_NO) { /* If NOT DISABLED, append NULL char (see Note #4). */
2652  *pstr_fmt = (CPU_CHAR)'\0';
2653  }
2654 
2655 
2656  if (fmt_invalid != DEF_NO) { /* Rtn NULL for invalid str fmt (see Notes #6a - #6d). */
2657  return ((CPU_CHAR *)0);
2658  }
2659 
2660 
2661  return (pstr); /* Rtn ptr to fmt'd str (see Note #6e). */
2662 }
2663 #endif
2664 
2665 
2666 /*$PAGE*/
2667 /*
2668 *********************************************************************************************************
2669 * Str_ParseNbr_Int32U()
2670 *
2671 * Description : Parse 32-bit unsigned integer from string.
2672 *
2673 * Argument(s) : pstr Pointer to string (see Notes #1 & #2a).
2674 *
2675 * pstr_next Optional pointer to a variable to ... :
2676 *
2677 * (a) Return a pointer to first character following the integer string,
2678 * if NO error(s) [see Note #2a2B2];
2679 * (b) Return a pointer to 'pstr',
2680 * otherwise (see Note #2a2A2).
2681 *
2682 * nbr_base Base of number to parse (see Notes #2a1B1 & #2a2B1).
2683 *
2684 * Return(s) : Parsed integer, if integer parsed with NO overflow (see Note #2a3A).
2685 *
2686 * DEF_INT_32U_MAX_VAL, if integer parsed but overflowed (see Note #2a3A1).
2687 *
2688 * 0, otherwise (see Note #2a3B).
2689 *
2690 * Caller(s) : Application.
2691 *
2692 * Note(s) : (1) String buffer NOT modified.
2693 *
2694 * (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : DESCRIPTION' states that "these
2695 * functions shall convert the initial portion of the string pointed to by 'str' ('pstr')
2696 * to a type unsigned long ... representation" :
2697 *
2698 * (1) "First, they decompose the input string into three parts" :
2699 *
2700 * (A) "An initial, possibly empty, sequence of white-space characters [as specified
2701 * by isspace()]."
2702 *
2703 * (1) "The subject sequence is defined as the longest initial subsequence of the
2704 * input string, starting with the first non-white-space character that is of
2705 * the expected form. The subject sequence shall contain no characters if the
2706 * input string is empty or consists entirely of white-space characters."
2707 *
2708 * (B) (1) "A subject sequence interpreted as an integer represented in some radix
2709 * determined by the value of 'base' ('nbr_base')" :
2710 *
2711 * (a) "If the value of 'base' ('nbr_base') is 0, the expected form of the
2712 * subject sequence is that of a decimal constant, octal constant, or
2713 * hexadecimal constant" :
2714 *
2715 * (1) "A decimal constant begins with a non-zero digit, and consists of a
2716 * sequence of decimal digits."
2717 *
2718 * (2) "An octal constant consists of the prefix '0' optionally followed by
2719 * a sequence of the digits '0' to '7' only."
2720 *
2721 * (3) "A hexadecimal constant consists of the prefix '0x' or '0X' followed
2722 * by a sequence of the decimal digits and letters 'a' (or 'A') to 'f'
2723 * (or 'F') with values 10 to 15 respectively."
2724 *
2725 * (b) "If the value of 'base' ('nbr_base') is between 2 and 36, the expected form
2726 * of the subject sequence is a sequence of letters and digits representing
2727 * an integer with the radix specified by 'base' ('nbr_base')" :
2728 *
2729 * (1) (A) "The letters from 'a' (or 'A') to 'z' (or 'Z') inclusive are
2730 * ascribed the values 10 to 35"; ...
2731 * (B) "only letters whose ascribed values are less than that of base
2732 * are permitted."
2733 *
2734 * (2) (A) "If the value of 'base' ('nbr_base') is 16, the characters '0x' or
2735 * '0X' may optionally precede the sequence of letters and digits."
2736 *
2737 * (B) Although NO specification states that "if the value of 'base'
2738 * ('nbr_base') is" 8, the '0' character "may optionally precede
2739 * the sequence of letters and digits"; it seems reasonable to
2740 * allow the '0' character to be optionally parsed.
2741 *
2742 * (2) "A subject sequence .... may be preceded by a '+' or '-' sign."
2743 *
2744 * (a) However, it does NOT seem reasonable to parse & convert a negative number
2745 * integer string into an unsigned integer.
2746 *
2747 * (C) (1) (a) "A final string of one or more unrecognized characters," ...
2748 * (b) "including the terminating null byte of the input string" ...
2749 * (2) "other than a sign or a permissible letter or digit."
2750 *$PAGE*
2751 * (2) Second, "they shall attempt to convert the subject sequence to an unsigned integer" :
2752 *
2753 * (A) "If the subject sequence is empty or does not have the expected form" :
2754 *
2755 * (1) "no conversion [is] performed"; ...
2756 * (2) "the value of 'str' ('pstr') [is] stored in the object pointed to by 'endptr'
2757 * ('pstr_next'), provided that 'endptr' ('pstr_next') is not a null pointer."
2758 *
2759 * (B) "If the subject sequence has the expected form" :
2760 *
2761 * (1) (a) "and the value of 'base' ('nbr_base') is 0, the sequence of characters
2762 * starting with the first digit shall be interpreted as an integer constant."
2763 *
2764 * (b) "and the value of 'base' ('nbr_base') is between 2 and 36, it shall be
2765 * used as the base for conversion, ascribing to each letter its value as
2766 * given above" (see Note #2a1B1b1A).
2767 *
2768 * (2) "A pointer to the final string shall be stored in the object pointed to by
2769 * 'endptr' ('pstr_next'), provided that 'endptr' ('pstr_next') is not a null
2770 * pointer."
2771 *
2772 * (3) Lastly, IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : RETURN VALUE' states that :
2773 *
2774 * (A) "Upon successful completion, these functions shall return the converted value."
2775 * (1) "If the correct value is outside the range of representable values, {ULONG_MAX}
2776 * ... shall be returned."
2777 *
2778 * (B) "If no conversion could be performed, 0 shall be returned."
2779 *
2780 * (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : ERRORS' states that "these functions
2781 * shall fail if" :
2782 *
2783 * (A) "[EINVAL] - The value of 'base' ('nbr_base') is not supported."
2784 *
2785 * (B) "[ERANGE] - The value to be returned is not representable."
2786 *
2787 * (2) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : ERRORS' states that "these functions
2788 * may fail if" :
2789 *
2790 * (A) "[EINVAL] - No conversion could be performed."
2791 *
2792 * (3) Return integer value & next string pointer should be used to diagnose parse success or failure :
2793 *
2794 * (a) Valid parse string integer :
2795 *
2796 * pstr = " ABCDE xyz"
2797 * nbr_base = 16
2798 *
2799 * nbr = 703710
2800 * pstr_next = " xyz"
2801 *
2802 *
2803 * (b) Invalid parse string integer :
2804 *
2805 * pstr = " ABCDE"
2806 * nbr_base = 10
2807 *
2808 * nbr = 0
2809 * pstr_next = pstr = " ABCDE"
2810 *
2811 *
2812 * (c) Valid hexadecimal parse string integer :
2813 *
2814 * pstr = " 0xGABCDE"
2815 * nbr_base = 16
2816 *
2817 * nbr = 0
2818 * pstr_next = "xGABCDE"
2819 *
2820 *
2821 * (d) Valid decimal parse string integer ('0x' prefix ignored
2822 * following invalid hexadecimal characters) :
2823 *
2824 * pstr = " 0xGABCDE"
2825 * nbr_base = 0
2826 *
2827 * nbr = 0
2828 * pstr_next = "xGABCDE"
2829 *
2830 *
2831 * (e) Valid decimal parse string integer ('0' prefix ignored
2832 * following invalid octal characters) :
2833 *
2834 * pstr = " 0GABCDE"
2835 * nbr_base = 0
2836 *
2837 * nbr = 0
2838 * pstr_next = "GABCDE"
2839 *
2840 *$PAGE*
2841 * (f) Parse string integer overflow :
2842 *
2843 * pstr = " 12345678901234567890*123456"
2844 * nbr_base = 10
2845 *
2846 * nbr = DEF_INT_32U_MAX_VAL
2847 * pstr_next = "*123456"
2848 *
2849 *
2850 * (g) Invalid negative unsigned parse string :
2851 *
2852 * pstr = " -12345678901234567890*123456"
2853 * nbr_base = 10
2854 *
2855 * nbr = 0
2856 * pstr_next = pstr = " -12345678901234567890*123456"
2857 *
2858 *********************************************************************************************************
2859 */
2860 
2862  CPU_CHAR **pstr_next,
2863  CPU_INT08U nbr_base)
2864 {
2865  CPU_INT32U nbr;
2866 
2867 
2868  nbr = Str_ParseNbr_Int32( pstr, /* Parse/convert str ... */
2869  pstr_next,
2870  nbr_base,
2871  DEF_NO, /* ... as unsigned int (see Note #2a2). */
2872  (CPU_BOOLEAN *)0);
2873 
2874  return (nbr);
2875 }
2876 
2877 
2878 /*$PAGE*/
2879 /*
2880 *********************************************************************************************************
2881 * Str_ParseNbr_Int32S()
2882 *
2883 * Description : Parse 32-bit signed integer from string.
2884 *
2885 * Argument(s) : pstr Pointer to string (see Notes #1 & #2a).
2886 *
2887 * pstr_next Optional pointer to a variable to ... :
2888 *
2889 * (a) Return a pointer to first character following the integer string,
2890 * if NO error(s) [see Note #2a2B2];
2891 * (b) Return a pointer to 'pstr',
2892 * otherwise (see Note #2a2A2).
2893 *
2894 * nbr_base Base of number to parse (see Notes #2a1B1 & #2a2B1).
2895 *
2896 * Return(s) : Parsed integer, if integer parsed with NO over- or underflow (see Note #2a3A).
2897 *
2898 * DEF_INT_32S_MIN_VAL, if integer parsed but negatively underflowed (see Note #2a3A1a).
2899 *
2900 * DEF_INT_32U_MAX_VAL, if integer parsed but positively overflowed (see Note #2a3A1b).
2901 *
2902 * 0, otherwise (see Note #2a3B).
2903 *
2904 * Caller(s) : Application.
2905 *
2906 * Note(s) : (1) String buffer NOT modified.
2907 *
2908 * (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strtol() : DESCRIPTION' states that "these
2909 * functions shall convert the initial portion of the string pointed to by 'str' ('pstr')
2910 * to a type long ... representation" :
2911 *
2912 * (1) "First, they decompose the input string into three parts" :
2913 *
2914 * (A) "An initial, possibly empty, sequence of white-space characters [as specified
2915 * by isspace()]."
2916 *
2917 * (1) "The subject sequence is defined as the longest initial subsequence of the
2918 * input string, starting with the first non-white-space character that is of
2919 * the expected form. The subject sequence shall contain no characters if the
2920 * input string is empty or consists entirely of white-space characters."
2921 *
2922 * (B) (1) "A subject sequence interpreted as an integer represented in some radix
2923 * determined by the value of 'base' ('nbr_base')" :
2924 *
2925 * (a) "If the value of 'base' ('nbr_base') is 0, the expected form of the
2926 * subject sequence is that of a decimal constant, octal constant, or
2927 * hexadecimal constant" :
2928 *
2929 * (1) "A decimal constant begins with a non-zero digit, and consists of a
2930 * sequence of decimal digits."
2931 *
2932 * (2) "An octal constant consists of the prefix '0' optionally followed by
2933 * a sequence of the digits '0' to '7' only."
2934 *
2935 * (3) "A hexadecimal constant consists of the prefix '0x' or '0X' followed
2936 * by a sequence of the decimal digits and letters 'a' (or 'A') to 'f'
2937 * (or 'F') with values 10 to 15 respectively."
2938 *
2939 * (b) "If the value of 'base' ('nbr_base') is between 2 and 36, the expected form
2940 * of the subject sequence is a sequence of letters and digits representing
2941 * an integer with the radix specified by 'base' ('nbr_base')" :
2942 *
2943 * (1) (A) "The letters from 'a' (or 'A') to 'z' (or 'Z') inclusive are
2944 * ascribed the values 10 to 35"; ...
2945 * (B) "only letters whose ascribed values are less than that of base
2946 * are permitted."
2947 *
2948 * (2) (A) "If the value of 'base' ('nbr_base') is 16, the characters '0x' or
2949 * '0X' may optionally precede the sequence of letters and digits."
2950 *
2951 * (B) Although NO specification states that "if the value of 'base'
2952 * ('nbr_base') is" 8, the '0' character "may optionally precede
2953 * the sequence of letters and digits"; it seems reasonable to
2954 * allow the '0' character to be optionally parsed.
2955 *
2956 * (2) "A subject sequence .... may be preceded by a '+' or '-' sign."
2957 *
2958 * (a) However, it does NOT seem reasonable to parse & convert a negative number
2959 * integer string into an unsigned integer.
2960 *
2961 * (C) (1) (a) "A final string of one or more unrecognized characters," ...
2962 * (b) "including the terminating null byte of the input string" ...
2963 * (2) "other than a sign or a permissible letter or digit."
2964 *$PAGE*
2965 * (2) Second, "they shall attempt to convert the subject sequence to an integer" :
2966 *
2967 * (A) "If the subject sequence is empty or does not have the expected form" :
2968 *
2969 * (1) "no conversion is performed"; ...
2970 * (2) "the value of 'str' ('pstr') is stored in the object pointed to by 'endptr'
2971 * ('pstr_next'), provided that 'endptr' ('pstr_next') is not a null pointer."
2972 *
2973 * (B) "If the subject sequence has the expected form" :
2974 *
2975 * (1) (a) "and the value of 'base' ('nbr_base') is 0, the sequence of characters
2976 * starting with the first digit shall be interpreted as an integer constant."
2977 *
2978 * (b) "and the value of 'base' ('nbr_base') is between 2 and 36, it shall be
2979 * used as the base for conversion, ascribing to each letter its value as
2980 * given above" (see Note #2a1B1b1A).
2981 *
2982 * (2) "A pointer to the final string shall be stored in the object pointed to by
2983 * 'endptr' ('pstr_next'), provided that 'endptr' ('pstr_next') is not a null
2984 * pointer."
2985 *
2986 * (3) Lastly, IEEE Std 1003.1, 2004 Edition, Section 'strtol() : RETURN VALUE' states that :
2987 *
2988 * (A) "Upon successful completion, these functions shall return the converted value."
2989 *
2990 * (1) "If the correct value is outside the range of representable values", either
2991 * of the following "shall be returned" :
2992 * (a) "{LONG_MIN}" or ...
2993 * (b) "{LONG_MAX}"
2994 *
2995 * (B) "If no conversion could be performed, 0 shall be returned."
2996 *
2997 * (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : ERRORS' states that "these functions
2998 * shall fail if" :
2999 *
3000 * (A) "[EINVAL] - The value of 'base' ('nbr_base') is not supported."
3001 *
3002 * (B) "[ERANGE] - The value to be returned is not representable."
3003 *
3004 * (2) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : ERRORS' states that "these functions
3005 * may fail if" :
3006 *
3007 * (A) "[EINVAL] - No conversion could be performed."
3008 *
3009 * (3) Return integer value & next string pointer should be used to diagnose parse success or failure :
3010 *
3011 * (a) Valid parse string integer :
3012 *
3013 * pstr = " ABCDE xyz"
3014 * nbr_base = 16
3015 *
3016 * nbr = 703710
3017 * pstr_next = " xyz"
3018 *
3019 *
3020 * (b) Invalid parse string integer :
3021 *
3022 * pstr = " ABCDE"
3023 * nbr_base = 10
3024 *
3025 * nbr = 0
3026 * pstr_next = pstr = " ABCDE"
3027 *
3028 *
3029 * (c) Valid hexadecimal parse string integer :
3030 *
3031 * pstr = " 0xGABCDE"
3032 * nbr_base = 16
3033 *
3034 * nbr = 0
3035 * pstr_next = "xGABCDE"
3036 *
3037 *
3038 * (d) Valid decimal parse string integer ('0x' prefix ignored
3039 * following invalid hexadecimal characters) :
3040 *
3041 * pstr = " 0xGABCDE"
3042 * nbr_base = 0
3043 *
3044 * nbr = 0
3045 * pstr_next = "xGABCDE"
3046 *
3047 *
3048 * (e) Valid decimal parse string integer ('0' prefix ignored
3049 * following invalid octal characters) :
3050 *
3051 * pstr = " 0GABCDE"
3052 * nbr_base = 0
3053 *
3054 * nbr = 0
3055 * pstr_next = "GABCDE"
3056 *
3057 *$PAGE*
3058 * (f) Parse string integer overflow :
3059 *
3060 * pstr = " 12345678901234567890*123456"
3061 * nbr_base = 10
3062 *
3063 * nbr = DEF_INT_32S_MAX_VAL
3064 * pstr_next = "*123456"
3065 *
3066 *
3067 * (g) Parse string integer underflow :
3068 *
3069 * pstr = " -12345678901234567890*123456"
3070 * nbr_base = 10
3071 *
3072 * nbr = DEF_INT_32S_MIN_VAL
3073 * pstr_next = "*123456"
3074 *
3075 *********************************************************************************************************
3076 */
3077 
3079  CPU_CHAR **pstr_next,
3080  CPU_INT08U nbr_base)
3081 {
3082  CPU_INT32S nbr;
3083  CPU_INT32U nbr_abs;
3084  CPU_BOOLEAN nbr_neg;
3085 
3086 
3087  nbr_abs = Str_ParseNbr_Int32(pstr, /* Parse/convert str ... */
3088  pstr_next,
3089  nbr_base,
3090  DEF_YES, /* ... as signed int (see Note #2a2). */
3091  &nbr_neg);
3092 
3093  if (nbr_neg == DEF_NO) { /* Chk for neg nbr & ovf/undf (see Note #2a3A1). */
3095  : (CPU_INT32S)nbr_abs;
3096  } else {
3098  : -(CPU_INT32S)nbr_abs;
3099  }
3100 
3101  return (nbr);
3102 }
3103 
3104 
3105 /*$PAGE*/
3106 /*
3107 *********************************************************************************************************
3108 *********************************************************************************************************
3109 * LOCAL FUNCTIONS
3110 *********************************************************************************************************
3111 *********************************************************************************************************
3112 */
3113 
3114 /*
3115 *********************************************************************************************************
3116 * Str_FmtNbr_Int32()
3117 *
3118 * Description : Format 32-bit integer into a multi-digit character string.
3119 *
3120 * Argument(s) : nbr Number to format.
3121 *
3122 * nbr_dig Number of digits to format (see Note #1).
3123 *
3124 * nbr_base Base of number to format (see Note #2).
3125 *
3126 * nbr_neg Indicates whether number to format is negative :
3127 * -------
3128 * DEF_NO Number is non-negative.
3129 * DEF_YES Number is negative.
3130 *
3131 * Argument validated in Str_FmtNbr_Int32U(),
3132 * Str_FmtNbr_Int32S().
3133 *
3134 * lead_char Prepend leading character (see Note #3) :
3135 *
3136 * '\0' Do NOT prepend leading character to string.
3137 * Printable character Prepend leading character to string.
3138 * Unprintable character Format invalid string (see Note #6e).
3139 *
3140 * lower_case Format alphabetic characters (if any) in lower case :
3141 *
3142 * DEF_NO Format alphabetic characters in upper case.
3143 * DEF_YES Format alphabetic characters in lower case.
3144 *
3145 * nul Append terminating NULL-character (see Note #4) :
3146 *
3147 * DEF_NO Do NOT append terminating NULL-character to string.
3148 * DEF_YES Append terminating NULL-character to string.
3149 *
3150 * pstr Pointer to character array to return formatted number string (see Note #5).
3151 *
3152 * Return(s) : Pointer to formatted string, if NO error(s) [see Note #6f].
3153 *
3154 * Pointer to NULL, otherwise.
3155 *
3156 * Caller(s) : Str_FmtNbr_Int32U(),
3157 * Str_FmtNbr_Int32S().
3158 *$PAGE*
3159 * Note(s) : (1) (a) The maximum number of digits to format for 32-bit integer numbers :
3160 *
3161 *
3162 * Maximum Number of [ log (Number) ]
3163 * 32-bit Integer Digits = floor [ -------------- + 1 ]
3164 * to Format [ log (Base) ]
3165 *
3166 * where
3167 * Number Number to format
3168 * Base Base of number to format
3169 *
3170 * (b) (1) If the number of digits to format ('nbr_dig') is zero; then NO formatting
3171 * is performed except possible NULL-termination of the string (see Note #4).
3172 *
3173 * Example :
3174 *
3175 * nbr = -23456
3176 * nbr_dig = 0
3177 * nbr_base = 10
3178 *
3179 * pstr = "" See Note #7a
3180 *
3181 * (2) If the number of digits to format ('nbr_dig') is less than the number of
3182 * significant integer digits of the number to format ('nbr'); then an invalid
3183 * string is formatted instead of truncating any significant integer digits.
3184 *
3185 * Example :
3186 *
3187 * nbr = 23456
3188 * nbr_dig = 3
3189 * nbr_base = 10
3190 *
3191 * pstr = "???" See Note #7b
3192 *
3193 * (3) If the number to format ('nbr') is negative but the number of digits to format
3194 * ('nbr_dig') is equal to the number of significant integer digits of the number
3195 * to format ('nbr'); then an invalid string is formatted instead of truncating
3196 * the negative sign.
3197 *
3198 * Example :
3199 *
3200 * nbr = -23456
3201 * nbr_dig = 5
3202 * nbr_base = 10
3203 *
3204 * pstr = "?????" See Note #7b
3205 *
3206 * (2) The number's base MUST be between 2 & 36, inclusive.
3207 *$PAGE*
3208 * (3) Leading character option prepends leading characters prior to the first non-zero digit.
3209 *
3210 * (a) (1) Leading character MUST be a printable ASCII character.
3211 *
3212 * (2) (A) Leading character MUST NOT be a number base digit, ...
3213 * (B) with the exception of '0'.
3214 *
3215 * (b) (1) The number of leading characters is such that the total number of significant
3216 * integer digits plus the number of leading characters plus possible negative
3217 * sign character is equal to the requested number of integer digits to format
3218 * ('nbr_dig').
3219 *
3220 * Examples :
3221 *
3222 * nbr = 23456
3223 * nbr_dig = 7
3224 * nbr_base = 10
3225 * lead_char = ' '
3226 *
3227 * pstr = " 23456"
3228 *
3229 *
3230 * nbr = -23456
3231 * nbr_dig = 7
3232 * nbr_base = 10
3233 * lead_char = ' '
3234 *
3235 * pstr = " -23456"
3236 *
3237 * (2) (A) If the number to format ('nbr') is negative AND the leading character
3238 * ('lead_char') is a '0' digit; then the negative sign character
3239 * prefixes all leading characters prior to the formatted number.
3240 *
3241 * Examples :
3242 *
3243 * nbr = -23456
3244 * nbr_dig = 8
3245 * nbr_base = 10
3246 * lead_char = '0'
3247 *
3248 * pstr = "-0023456"
3249 *
3250 *
3251 * nbr = -43981
3252 * nbr_dig = 8
3253 * nbr_base = 16
3254 * lead_char = '0'
3255 * lower_case = DEF_NO
3256 *
3257 * pstr = "-000ABCD"
3258 *
3259 * (B) If the number to format ('nbr') is negative AND the leading character
3260 * ('lead_char') is NOT a '0' digit; then the negative sign character
3261 * immediately prefixes the most significant digit of the formatted number.
3262 *
3263 * Examples :
3264 *
3265 * nbr = -23456
3266 * nbr_dig = 8
3267 * nbr_base = 10
3268 * lead_char = '#'
3269 *
3270 * pstr = "##-23456"
3271 *
3272 *
3273 * nbr = -43981
3274 * nbr_dig = 8
3275 * nbr_base = 16
3276 * lead_char = '#'
3277 * lower_case = DEF_YES
3278 *
3279 * pstr = "###-abcd"
3280 *
3281 * (c) (1) If the value of the number to format is zero ...
3282 * (2) ... & the number of digits to format is non-zero, ...
3283 * (3) ... but NO leading character available; ...
3284 * (4) ... then one digit of '0' value is formatted.
3285 *
3286 * This is NOT a leading character; but a single integer digit of '0' value.
3287 *$PAGE*
3288 * (4) (a) NULL-character terminate option DISABLED prevents overwriting previous character
3289 * array formatting.
3290 *
3291 * (b) WARNING: Unless 'pstr' character array is pre-/post-terminated, NULL-character
3292 * terminate option DISABLED will cause character string run-on.
3293 *
3294 * (5) (a) Format buffer size NOT validated; buffer overruns MUST be prevented by caller.
3295 *
3296 * (b) To prevent character buffer overrun :
3297 *
3298 * Character array size MUST be >= ('nbr_dig' +
3299 * 1 negative sign +
3300 * 1 'NUL' terminator) characters
3301 *
3302 * (6) String format terminates when :
3303 *
3304 * (a) Format string pointer is passed a NULL pointer.
3305 * (1) No string formatted; NULL pointer returned.
3306 *
3307 * (b) Number of digits to format ('nbr_dig') is zero.
3308 * (1) NULL string formatted (see Note #7a); NULL pointer returned.
3309 *
3310 * (c) Number of digits to format ('nbr_dig') is less than number of significant
3311 * integer digits of the number to format ('nbr'), including possible
3312 * negative sign.
3313 * (1) Invalid string formatted (see Note #7); NULL pointer returned.
3314 *
3315 * (d) Base is passed an invalid base (see Note #2).
3316 * (1) Invalid string format performed; NULL pointer returned.
3317 *
3318 * (e) Lead character is NOT a valid, printable character (see Note #3a).
3319 * (1) Invalid string formatted (see Note #7); NULL pointer returned.
3320 *
3321 * (f) Number successfully formatted into character string array.
3322 *
3323 * (7) For any unsuccessful string format or error(s), an invalid string of question marks
3324 * ('?') will be formatted, where the number of question marks is determined by the
3325 * number of digits to format ('nbr_dig') :
3326 *
3327 * Invalid string's { (a) 0 (NULL string) , if 'nbr_dig' = 0
3328 * number of = {
3329 * question marks { (b) 'nbr_dig' , if 'nbr_dig' > 0
3330 *
3331 *********************************************************************************************************
3332 */
3333 
3335  CPU_INT08U nbr_dig,
3336  CPU_INT08U nbr_base,
3337  CPU_BOOLEAN nbr_neg,
3338  CPU_CHAR lead_char,
3339  CPU_BOOLEAN lower_case,
3340  CPU_BOOLEAN nul,
3341  CPU_CHAR *pstr)
3342 {
3343  CPU_CHAR *pstr_fmt;
3344  CPU_INT32U nbr_fmt;
3345  CPU_INT32U nbr_log;
3346  CPU_INT08U nbr_dig_max;
3347  CPU_INT08U nbr_dig_min;
3348  CPU_INT08U nbr_dig_fmtd;
3349  CPU_INT08U nbr_neg_sign;
3350  CPU_INT08U nbr_lead_char;
3351  CPU_INT08U dig_val;
3352  CPU_INT08U i;
3353  CPU_INT08U lead_char_delta_0;
3354  CPU_INT08U lead_char_delta_a;
3355  CPU_BOOLEAN lead_char_dig;
3356  CPU_BOOLEAN lead_char_0;
3357  CPU_BOOLEAN fmt_invalid;
3358  CPU_BOOLEAN print_char;
3359  CPU_BOOLEAN nbr_neg_fmtd;
3360 
3361 
3362 /*$PAGE*/
3363  /* ---------------- VALIDATE FMT ARGS ----------------- */
3364  if (pstr == (CPU_CHAR *)0) { /* Rtn NULL if str ptr NULL (see Note #6a). */
3365  return ((CPU_CHAR *)0);
3366  }
3367 
3368  fmt_invalid = DEF_NO;
3369 
3370  if (nbr_dig < 1) { /* If nbr digs = 0, ... */
3371  fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6b). */
3372  }
3373  /* If invalid base, ... */
3374  if ((nbr_base < 2) ||
3375  (nbr_base > 36)) {
3376  fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6d). */
3377  }
3378 
3379  if (lead_char != (CPU_CHAR)'\0') {
3380  print_char = ASCII_IsPrint(lead_char);
3381  if (print_char != DEF_YES) { /* If lead char non-printable (see Note #3a1), ... */
3382  fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6e). */
3383 
3384  } else if (lead_char != '0') { /* Chk lead char for non-0 nbr base dig. */
3385  lead_char_delta_0 = (CPU_INT08U)(lead_char - '0');
3386  if (lower_case != DEF_YES) {
3387  lead_char_delta_a = (CPU_INT08U)(lead_char - 'A');
3388  } else {
3389  lead_char_delta_a = (CPU_INT08U)(lead_char - 'a');
3390  }
3391 
3392  lead_char_dig = (((nbr_base <= 10) && (lead_char_delta_0 < nbr_base)) ||
3393  ((nbr_base > 10) && ((lead_char_delta_0 < 10) ||
3394  (lead_char_delta_a < (nbr_base - 10))))) ? DEF_YES : DEF_NO;
3395 
3396  if (lead_char_dig == DEF_YES) { /* If lead char non-0 nbr base dig (see Note #3a2A), ...*/
3397  fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6e). */
3398  }
3399  }
3400  }
3401 
3402 
3403  /* ----------------- PREPARE NBR FMT ------------------ */
3404  pstr_fmt = pstr;
3405 
3406  if (fmt_invalid == DEF_NO) {
3407  nbr_fmt = nbr;
3408  nbr_log = nbr;
3409  nbr_dig_max = 1u;
3410  while (nbr_log >= nbr_base) { /* While nbr base digs avail, ... */
3411  nbr_dig_max++; /* ... calc max nbr digs. */
3412  nbr_log /= nbr_base;
3413  }
3414 
3415  nbr_neg_sign = (nbr_neg == DEF_YES) ? 1u : 0u;
3416  if (nbr_dig >= (nbr_dig_max + nbr_neg_sign)) { /* If req'd nbr digs >= (max nbr digs + neg sign), ... */
3417  nbr_neg_fmtd = DEF_NO;
3418  nbr_dig_min = DEF_MIN(nbr_dig_max, nbr_dig);
3419  /* ... calc nbr digs to fmt & nbr lead chars. */
3420  if (lead_char != (CPU_CHAR)'\0') {
3421  nbr_dig_fmtd = nbr_dig;
3422  nbr_lead_char = nbr_dig -
3423  nbr_dig_min - nbr_neg_sign;
3424  } else {
3425  nbr_dig_fmtd = nbr_dig_min + nbr_neg_sign;
3426  nbr_lead_char = 0u;
3427  }
3428 
3429  if (nbr_lead_char > 0) { /* If lead chars to fmt, ... */
3430  lead_char_0 = (lead_char == '0') /* ... chk if lead char a '0' dig (see Note #3a2B). */
3431  ? DEF_YES : DEF_NO;
3432  } else {
3433  lead_char_0 = DEF_NO;
3434  }
3435 
3436  } else { /* Else if nbr trunc'd, ... */
3437  fmt_invalid = DEF_YES; /* ... fmt invalid str (see Note #6c). */
3438  }
3439  }
3440 
3441  if (fmt_invalid != DEF_NO) {
3442  nbr_dig_fmtd = nbr_dig;
3443  }
3444 
3445 
3446 /*$PAGE*/
3447  /* ------------------- FMT NBR STR -------------------- */
3448  pstr_fmt += nbr_dig_fmtd; /* Start fmt @ least-sig dig. */
3449 
3450  if (nul != DEF_NO) { /* If NOT DISABLED, append NULL char (see Note #4). */
3451  *pstr_fmt = (CPU_CHAR)'\0';
3452  }
3453  pstr_fmt--;
3454 
3455 
3456  for (i = 0u; i < nbr_dig_fmtd; i++) { /* Fmt str for desired nbr digs : */
3457  if (fmt_invalid == DEF_NO) {
3458  if ((nbr_fmt > 0) || /* If fmt nbr > 0 ... */
3459  (i == 0)) { /* ... OR on one's dig to fmt (see Note #3c1), ... */
3460  /* ... calc & fmt dig val; ... */
3461  dig_val = (CPU_INT08U)(nbr_fmt % nbr_base);
3462  if (dig_val <= 9) {
3463  *pstr_fmt-- = (CPU_CHAR)(dig_val + '0');
3464  } else {
3465  if (lower_case != DEF_YES) {
3466  *pstr_fmt-- = (CPU_CHAR)((dig_val - 10u) + 'A');
3467  } else {
3468  *pstr_fmt-- = (CPU_CHAR)((dig_val - 10u) + 'a');
3469  }
3470  }
3471 
3472  nbr_fmt /= nbr_base; /* Shift to next more-sig dig. */
3473 
3474  } else if ((nbr_neg == DEF_YES) && /* ... else if nbr neg AND ... */
3475  (((lead_char_0 == DEF_NO ) && /* ... lead char NOT a '0' dig ... */
3476  (nbr_neg_fmtd == DEF_NO )) || /* ... but neg sign NOT yet fmt'd OR ... */
3477  ((lead_char_0 != DEF_NO ) && /* ... lead char is a '0' dig ... */
3478  (i == (nbr_dig_fmtd - 1))))) { /* ... & on most-sig dig to fmt, ... */
3479 
3480  *pstr_fmt-- = '-'; /* ... prepend neg sign (see Note #3b); ... */
3481  nbr_neg_fmtd = DEF_YES;
3482 
3483  } else if (lead_char != (CPU_CHAR)'\0') { /* ... else if avail, ... */
3484  *pstr_fmt-- = lead_char; /* ... fmt lead char. */
3485  }
3486 
3487  } else { /* Else fmt '?' for invalid str (see Note #7). */
3488  *pstr_fmt-- = '?';
3489  }
3490  }
3491 
3492 
3493  if (fmt_invalid != DEF_NO) { /* Rtn NULL for invalid str fmt (see Notes #6a - #6e). */
3494  return ((CPU_CHAR *)0);
3495  }
3496 
3497 
3498  return (pstr); /* Rtn ptr to fmt'd str (see Note #6f). */
3499 }
3500 
3501 
3502 /*$PAGE*/
3503 /*
3504 *********************************************************************************************************
3505 * Str_ParseNbr_Int32()
3506 *
3507 * Description : Parse 32-bit integer from string.
3508 *
3509 * Argument(s) : pstr Pointer to string (see Notes #1 & #2a).
3510 *
3511 * pstr_next Optional pointer to a variable to ... :
3512 *
3513 * (a) Return a pointer to first character following the integer string,
3514 * if NO error(s) [see Note #2a2B2];
3515 * (b) Return a pointer to 'pstr',
3516 * otherwise (see Note #2a2A2).
3517 *
3518 * nbr_base Base of number to parse (see Notes #2a1B1 & #2a2B1).
3519 *
3520 * nbr_signed Indicates whether number to parse is signed :
3521 *
3522 * DEF_NO Number is unsigned.
3523 * DEF_YES Number is signed.
3524 *
3525 * pnbr_neg Pointer to a variable to return if the parsed (signed) number is negative :
3526 *
3527 * DEF_NO Number is non-negative.
3528 * DEF_YES Number is negative.
3529 *
3530 * Return(s) : Parsed integer, if integer parsed with NO overflow (see Note #2a3A).
3531 *
3532 * DEF_INT_32U_MAX_VAL, if integer parsed but overflowed (see Note #2a3A1).
3533 *
3534 * 0, otherwise (see Note #2a3B).
3535 *
3536 * Caller(s) : Str_ParseNbr_Int32U(),
3537 * Str_ParseNbr_Int32S().
3538 *
3539 * Note(s) : (1) String buffer NOT modified.
3540 *
3541 * (2) (a) IEEE Std 1003.1, 2004 Edition, Section 'strtol() : DESCRIPTION' states that "these
3542 * functions shall convert the initial portion of the string pointed to by 'str' ('pstr')
3543 * to a type long ... representation" :
3544 *
3545 * (1) "First, they decompose the input string into three parts" :
3546 *
3547 * (A) "An initial, possibly empty, sequence of white-space characters [as specified
3548 * by isspace()]."
3549 *
3550 * (1) "The subject sequence is defined as the longest initial subsequence of the
3551 * input string, starting with the first non-white-space character that is of
3552 * the expected form. The subject sequence shall contain no characters if the
3553 * input string is empty or consists entirely of white-space characters."
3554 *
3555 * (B) (1) "A subject sequence interpreted as an integer represented in some radix
3556 * determined by the value of 'base' ('nbr_base')" :
3557 *
3558 * (a) "If the value of 'base' ('nbr_base') is 0, the expected form of the
3559 * subject sequence is that of a decimal constant, octal constant, or
3560 * hexadecimal constant" :
3561 *
3562 * (1) "A decimal constant begins with a non-zero digit, and consists of a
3563 * sequence of decimal digits."
3564 *
3565 * (2) "An octal constant consists of the prefix '0' optionally followed by
3566 * a sequence of the digits '0' to '7' only."
3567 *
3568 * (3) "A hexadecimal constant consists of the prefix '0x' or '0X' followed
3569 * by a sequence of the decimal digits and letters 'a' (or 'A') to 'f'
3570 * (or 'F') with values 10 to 15 respectively."
3571 *
3572 * (b) "If the value of 'base' ('nbr_base') is between 2 and 36, the expected form
3573 * of the subject sequence is a sequence of letters and digits representing
3574 * an integer with the radix specified by 'base' ('nbr_base')" :
3575 *
3576 * (1) (A) "The letters from 'a' (or 'A') to 'z' (or 'Z') inclusive are
3577 * ascribed the values 10 to 35"; ...
3578 * (B) "only letters whose ascribed values are less than that of base
3579 * are permitted."
3580 *
3581 * (2) (A) "If the value of 'base' ('nbr_base') is 16, the characters '0x' or
3582 * '0X' may optionally precede the sequence of letters and digits."
3583 *
3584 * (B) Although NO specification states that "if the value of 'base'
3585 * ('nbr_base') is" 8, the '0' character "may optionally precede
3586 * the sequence of letters and digits"; it seems reasonable to
3587 * allow the '0' character to be optionally parsed.
3588 *$PAGE*
3589 * (2) "A subject sequence .... may be preceded by a '+' or '-' sign."
3590 *
3591 * (a) It does NOT seem reasonable to parse & convert a negative number
3592 * integer string into an unsigned integer. However, a negative sign
3593 * for an unsigned integer will automatically be parsed as an invalid
3594 * character (see Note #2aC1).
3595 *
3596 * (C) (1) (a) "A final string of one or more unrecognized characters," ...
3597 * (b) "including the terminating null byte of the input string" ...
3598 * (2) "other than a sign or a permissible letter or digit."
3599 *
3600 * (2) Second, "they shall attempt to convert the subject sequence to an integer" :
3601 *
3602 * (A) "If the subject sequence is empty or does not have the expected form" :
3603 *
3604 * (1) "no conversion is performed"; ...
3605 * (2) "the value of 'str' ('pstr') is stored in the object pointed to by 'endptr'
3606 * ('pstr_next'), provided that 'endptr' ('pstr_next') is not a null pointer."
3607 *
3608 * (B) "If the subject sequence has the expected form" :
3609 *
3610 * (1) (a) "and the value of 'base' ('nbr_base') is 0, the sequence of characters
3611 * starting with the first digit shall be interpreted as an integer constant."
3612 *
3613 * (b) "and the value of 'base' ('nbr_base') is between 2 and 36, it shall be
3614 * used as the base for conversion, ascribing to each letter its value as
3615 * given above" (see Note #2a1B1b1A).
3616 *
3617 * (2) "A pointer to the final string shall be stored in the object pointed to by
3618 * 'endptr' ('pstr_next'), provided that 'endptr' ('pstr_next') is not a null
3619 * pointer."
3620 *
3621 * (3) Lastly, IEEE Std 1003.1, 2004 Edition, Section 'strtol() : RETURN VALUE' states that :
3622 *
3623 * (A) "Upon successful completion, these functions shall return the converted value."
3624 * (1) "If the correct value is outside the range of representable values, {LONG_MIN}
3625 * [or] {LONG_MAX} ... shall be returned."
3626 *
3627 * (B) "If no conversion could be performed, 0 shall be returned."
3628 *
3629 * (b) (1) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : ERRORS' states that "these functions
3630 * shall fail if" :
3631 *
3632 * (A) "[EINVAL] - The value of 'base' ('nbr_base') is not supported."
3633 *
3634 * (B) "[ERANGE] - The value to be returned is not representable."
3635 *
3636 * (2) IEEE Std 1003.1, 2004 Edition, Section 'strtoul() : ERRORS' states that "these functions
3637 * may fail if" :
3638 *
3639 * (A) "[EINVAL] - No conversion could be performed."
3640 *$PAGE*
3641 * (3) Return integer value & next string pointer should be used to diagnose parse success or failure :
3642 *
3643 * (a) Valid parse string integer :
3644 *
3645 * pstr = " ABCDE xyz"
3646 * nbr_base = 16
3647 *
3648 * nbr = 703710
3649 * pstr_next = " xyz"
3650 *
3651 *
3652 * (b) Invalid parse string integer :
3653 *
3654 * pstr = " ABCDE"
3655 * nbr_base = 10
3656 *
3657 * nbr = 0
3658 * pstr_next = pstr = " ABCDE"
3659 *
3660 *
3661 * (c) Valid hexadecimal parse string integer :
3662 *
3663 * pstr = " 0xGABCDE"
3664 * nbr_base = 16
3665 *
3666 * nbr = 0
3667 * pstr_next = "xGABCDE"
3668 *
3669 *
3670 * (d) Valid decimal parse string integer ('0x' prefix ignored
3671 * following invalid hexadecimal characters) :
3672 *
3673 * pstr = " 0xGABCDE"
3674 * nbr_base = 0
3675 *
3676 * nbr = 0
3677 * pstr_next = "xGABCDE"
3678 *
3679 *
3680 * (e) Valid decimal parse string integer ('0' prefix ignored
3681 * following invalid octal characters) :
3682 *
3683 * pstr = " 0GABCDE"
3684 * nbr_base = 0
3685 *
3686 * nbr = 0
3687 * pstr_next = "GABCDE"
3688 *
3689 *
3690 * (f) Parse string integer overflow :
3691 *
3692 * pstr = " 12345678901234567890*123456"
3693 * nbr_base = 10
3694 *
3695 * nbr = DEF_INT_32U_MAX_VAL
3696 * pstr_next = "*123456"
3697 *
3698 *
3699 * (g) Parse string integer underflow :
3700 *
3701 * pstr = " -12345678901234567890*123456"
3702 * nbr_base = 10
3703 *
3704 * nbr = DEF_INT_32S_MIN_VAL
3705 * pstr_next = "*123456"
3706 *
3707 *
3708 * (4) String parse terminates when :
3709 *
3710 * (a) Base passed an invalid base (see Note #2a1B1b).
3711 * (1) No conversion performed; 0 returned.
3712 *
3713 * (b) (1) Parse string passed a NULL pointer OR empty integer sequence (see Note #2a2A).
3714 * (A) No conversion performed; 0 returned.
3715 *
3716 * (2) Invalid parse string character found (see Note #2a1C).
3717 * (A) Parsed integer returned.
3718 * (B) 'pstr_next' points to invalid character.
3719 *
3720 * (3) Entire parse string converted (see Note #2a2B).
3721 * (A) Parsed integer returned.
3722 * (B) 'pstr_next' points to terminating NULL character.
3723 *
3724 * (5) Pointers to variables that return values MUST be initialized PRIOR to all other
3725 * validation or function handling in case of any error(s).
3726 *********************************************************************************************************
3727 */
3728 /*$PAGE*/
3730  CPU_CHAR **pstr_next,
3731  CPU_INT08U nbr_base,
3732  CPU_BOOLEAN nbr_signed,
3733  CPU_BOOLEAN *pnbr_neg)
3734 {
3735  const CPU_CHAR *pstr_parse;
3736  const CPU_CHAR *pstr_parse_nbr;
3737  CPU_CHAR *pstr_parse_unused;
3738  CPU_CHAR parse_char;
3739  CPU_INT08U parse_dig;
3740  CPU_INT32U nbr;
3741  CPU_BOOLEAN nbr_neg_unused;
3742  CPU_BOOLEAN nbr_dig;
3743  CPU_BOOLEAN nbr_alpha;
3744  CPU_BOOLEAN nbr_hex;
3745  CPU_BOOLEAN nbr_hex_lower;
3746  CPU_BOOLEAN whitespace;
3747  CPU_BOOLEAN neg;
3748  CPU_BOOLEAN ovf;
3749  CPU_BOOLEAN done;
3750 
3751  /* --------------- VALIDATE PARSE ARGS ---------------- */
3752  if (pstr_next == (CPU_CHAR **) 0) { /* If NOT avail, ... */
3753  pstr_next = (CPU_CHAR **)&pstr_parse_unused; /* ... re-cfg NULL rtn ptr to unused local var. */
3754  (void)&pstr_parse_unused; /* Prevent possible 'variable unused' warning. */
3755  }
3756  *pstr_next = (CPU_CHAR *)pstr; /* Init rtn str for err (see Note #5). */
3757 
3758  if (pnbr_neg == (CPU_BOOLEAN *) 0) { /* If NOT avail, ... */
3759  pnbr_neg = (CPU_BOOLEAN *)&nbr_neg_unused; /* ... re-cfg NULL rtn ptr to unused local var. */
3760  (void)&nbr_neg_unused; /* Prevent possible 'variable unused' warning. */
3761  }
3762  *pnbr_neg = DEF_NO; /* Init nbr neg for err (see Note #5). */
3763 
3764 
3765  if (pstr == (CPU_CHAR *)0) { /* Rtn zero if str ptr NULL (see Note #4b1). */
3766  return (0u);
3767  }
3768  /* Rtn zero if invalid base (see Note #4a). */
3769  if ((nbr_base == 1) ||
3770  (nbr_base > 36)) {
3771  return (0u);
3772  }
3773 
3774 
3775  /* ------------- IGNORE PRECEDING CHAR(S) ------------- */
3776  pstr_parse = pstr; /* Save ptr to init'l str for err (see Note #2a2A2). */
3777 
3778  whitespace = ASCII_IsSpace(*pstr_parse);
3779  while (whitespace == DEF_YES) { /* Ignore initial white-space char(s) [see Note #2a1A]. */
3780  pstr_parse++;
3781  whitespace = ASCII_IsSpace(*pstr_parse);
3782  }
3783 
3784  switch (*pstr_parse) {
3785  case '+': /* Ignore pos sign (see Note #2a1B2). */
3786  pstr_parse++;
3787  neg = DEF_NO;
3788  break;
3789 
3790 
3791  case '-': /* Validate neg sign (see Note #2a1B2a). */
3792  if (nbr_signed == DEF_YES) {
3793  pstr_parse++;
3794  }
3795  neg = DEF_YES;
3796  break;
3797 
3798 
3799  default:
3800  neg = DEF_NO;
3801  break;
3802  }
3803 
3804 
3805 /*$PAGE*/
3806  /* --------- IGNORE NBR BASE PRECEDING CHAR(S) -------- */
3807  pstr_parse_nbr = pstr_parse; /* Save ptr to str's nbr (see Note #2a1A1). */
3808 
3809  switch (nbr_base) {
3810  case 0u: /* Determine unspecified nbr base (see Notes #2a1B1a). */
3811  if (*pstr_parse == '0') { /* If avail, ... */
3812  pstr_parse++; /* ... adv past '0' prefix (see Note #2a1B1b2). */
3813  switch (*pstr_parse) {
3814  case 'x': /* For '0x' prefix, ... */
3815  case 'X':
3816  nbr_base = 16u; /* ... set nbr base = 16 (see Note #2a1B1a3). */
3817  parse_char = (CPU_CHAR)(*(pstr_parse + 1));
3818  nbr_hex = ASCII_IsDigHex(parse_char);
3819  if (nbr_hex == DEF_YES) { /* If next char is valid hex dig, ... */
3820  pstr_parse++; /* ... adv past '0x' prefix (see Note #2a1B1b2A). */
3821  }
3822  break;
3823 
3824 
3825  default: /* For '0' prefix, ... */
3826  nbr_base = 8u; /* ... set nbr base = 8 (see Note #2a1B1a2). */
3827  break;
3828  }
3829 
3830  } else { /* For non-'0' prefix, ... */
3831  nbr_base = 10u; /* ... set nbr base = 10 (see Note #2a1B1a1). */
3832  }
3833  break;
3834 
3835 
3836  case 8u: /* See Note #2a1B1a2. */
3837  if (*pstr_parse == '0') { /* If avail, ... */
3838  pstr_parse++; /* ... adv past '0' prefix (see Note #2a1B1b2B). */
3839  }
3840  break;
3841 
3842 
3843  case 16u: /* See Note #2a1B1a3. */
3844  if (*pstr_parse == '0') { /* If avail, ... */
3845  pstr_parse++; /* ... adv past '0' prefix (see Note #2a1B1b2). */
3846  switch (*pstr_parse) {
3847  case 'x':
3848  case 'X':
3849  parse_char = (CPU_CHAR)(*(pstr_parse + 1));
3850  nbr_hex = ASCII_IsDigHex(parse_char);
3851  if (nbr_hex == DEF_YES) { /* If next char is valid hex dig, ... */
3852  pstr_parse++; /* ... adv past '0x' prefix (see Note #2a1B1b2A). */
3853  }
3854  break;
3855 
3856 
3857  default:
3858  break;
3859  }
3860  }
3861  break;
3862 
3863 
3864  default: /* See Note #2a1B1b. */
3865  break;
3866  }
3867 
3868 
3869 /*$PAGE*/
3870  /* ------------------ PARSE INT STR ------------------- */
3871  nbr = 0u;
3872  ovf = DEF_NO;
3873  done = DEF_NO;
3874 
3875  while (done == DEF_NO) { /* Parse str for desired nbr base digs (see Note #2a2). */
3876  parse_char = (CPU_CHAR)*pstr_parse;
3877  nbr_alpha = ASCII_IsAlphaNum(parse_char);
3878  if (nbr_alpha == DEF_YES) { /* If valid alpha num nbr dig avail, ... */
3879  /* ... convert parse char into nbr dig. */
3880  nbr_dig = ASCII_IsDig(parse_char);
3881  if (nbr_dig == DEF_YES) {
3882  parse_dig = (CPU_INT08U)(parse_char - '0');
3883  } else {
3884  nbr_hex_lower = ASCII_IsLower(parse_char);
3885  if (nbr_hex_lower == DEF_YES) {
3886  parse_dig = (CPU_INT08U)((parse_char - 'a') + 10u);
3887  } else {
3888  parse_dig = (CPU_INT08U)((parse_char - 'A') + 10u);
3889  }
3890  }
3891 
3892  if (parse_dig < nbr_base) { /* If parse char valid for nbr base ... */
3893  if (ovf == DEF_NO) { /* ... & nbr NOT yet ovf'd, ... */
3894  if (nbr <= Str_MultOvfThTbl_Int32U[nbr_base]) {
3895  /* ... merge parse char dig into nbr. */
3896  nbr *= nbr_base;
3897  nbr += parse_dig;
3898  if (nbr < parse_dig) {
3899  ovf = DEF_YES;
3900  }
3901  } else {
3902  ovf = DEF_YES;
3903  }
3904  }
3905  pstr_parse++;
3906 
3907  } else { /* Invalid char parsed (see Note #2a1C1a). */
3908  done = DEF_YES;
3909  }
3910 
3911  } else { /* Invalid OR NULL char parsed (see Note #2a1C1). */
3912  done = DEF_YES;
3913  }
3914  }
3915 
3916  if (ovf == DEF_YES) { /* If nbr ovf'd, ... */
3917  nbr = DEF_INT_32U_MAX_VAL; /* ... rtn max int val (see Note #2a3A1). */
3918  }
3919 
3920 
3921  if (pstr_parse != pstr_parse_nbr) { /* If final parse str != init'l parse nbr str, .. */
3922  *pstr_next = (CPU_CHAR *)pstr_parse; /* .. rtn parse str's next char (see Note #2a2B2); .. */
3923  } else {
3924  *pstr_next = (CPU_CHAR *)pstr; /* .. else rtn initial parse str (see Note #2a2A2). */
3925  }
3926 
3927  *pnbr_neg = neg; /* Rtn neg nbr status. */
3928 
3929 
3930  return (nbr);
3931 }
3932