1 /**
2 * Copyright (c) 2019, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 =======================================================================
32
33 FILE: std.c
34
35 SERVICES: apiOne std lib string stuff
36
37 =======================================================================
38 */
39
40 //
41 // someday, drop this #include, implement our own memmove()
42 //
43 #include <stddef.h>
44 #include "AEEstd.h"
45 #include "version.h"
46
std_getversion(char * pcDst,int nDestSize)47 int std_getversion(char *pcDst, int nDestSize)
48 {
49 return std_strlcpy(pcDst, VERSION_STRING, nDestSize);
50 }
51
52
std_tolower(char c)53 char std_tolower(char c)
54 {
55 if ((c >= 'A') && (c <= 'Z')) {
56 c |= 32;
57 }
58 return c;
59 }
60
std_toupper(char c)61 char std_toupper(char c)
62 {
63 if ((c >= 'a') && (c <= 'z')) {
64 c &= ~32;
65 }
66 return c;
67 }
68
69
x_casecmp(unsigned char c1,unsigned char c2)70 static __inline int x_casecmp(unsigned char c1, unsigned char c2)
71 {
72 int diff = c1 - c2;
73 if (c1 >= 'A' && c1 <= 'Z') {
74 diff += 32;
75 }
76 if (c2 >= 'A' && c2 <= 'Z') {
77 diff -= 32;
78 }
79 return diff;
80 }
81
82
std_strncmp(const char * s1,const char * s2,int n)83 int std_strncmp(const char* s1, const char* s2, int n)
84 {
85 if (n > 0) {
86 int i = 0;
87
88 do {
89 unsigned char c1 = (unsigned char)s1[i];
90 unsigned char c2 = (unsigned char)s2[i];
91 int diff = c1 - c2;
92
93 if (diff) {
94 return diff;
95 }
96
97 if ('\0' == c1) {
98 break;
99 }
100 i++;
101 } while (i < n);
102 }
103
104 return 0;
105 }
106
std_strcmp(const char * s1,const char * s2)107 int std_strcmp(const char* s1, const char* s2)
108 {
109 return std_strncmp(s1, s2, MAX_INT32);
110 }
111
std_strnicmp(const char * s1,const char * s2,int n)112 int std_strnicmp(const char* s1, const char* s2, int n)
113 {
114 if (n > 0) {
115 int i = -n;
116
117 s1 += n;
118 s2 += n;
119
120 do {
121 unsigned char c1 = (unsigned char)s1[i];
122 unsigned char c2 = (unsigned char)s2[i];
123
124 int diff = x_casecmp(c1,c2);
125 if (diff) {
126 return diff;
127 }
128 if ('\0' == c1) {
129 break;
130 }
131 } while (++i);
132 }
133 return 0;
134 }
135
std_stricmp(const char * s1,const char * s2)136 int std_stricmp(const char* s1, const char* s2)
137 {
138 return std_strnicmp(s1, s2, MAX_INT32);
139 }
140
std_strlcpy(char * pcDst,const char * cpszSrc,int nDestSize)141 int std_strlcpy(char* pcDst, const char* cpszSrc, int nDestSize)
142 {
143 int nLen = std_strlen(cpszSrc);
144
145 if (0 < nDestSize) {
146 int n;
147
148 n = STD_MIN(nLen, nDestSize - 1);
149 (void)std_memmove(pcDst, cpszSrc, n);
150
151 pcDst[n] = 0;
152 }
153
154 return nLen;
155 }
156
std_strlcat(char * pcDst,const char * cpszSrc,int nDestSize)157 int std_strlcat(char* pcDst, const char* cpszSrc, int nDestSize)
158 {
159 int nLen = 0;
160
161 while ((nLen < nDestSize) && (0 != pcDst[nLen])) {
162 ++nLen;
163 }
164
165 return nLen + std_strlcpy(pcDst+nLen, cpszSrc, nDestSize-nLen);
166 }
167
std_strstr(const char * cpszHaystack,const char * cpszNeedle)168 char* std_strstr(const char* cpszHaystack, const char* cpszNeedle)
169 {
170 /* Check the empty needle string as a special case */
171 if ('\0' == *cpszNeedle ) {
172 return (char*)cpszHaystack;
173 }
174
175 while ('\0' != *cpszHaystack) {
176 /* Find the first character of the needle string in the haystack string */
177 if (*cpszHaystack == *cpszNeedle) {
178 /* check if the rest of the string matches */
179 const char* pHaystack = cpszHaystack;
180 const char* pNeedle = cpszNeedle;
181 do {
182 if ('\0' == *++pNeedle) {
183 /* Found a match */
184 return (char*)cpszHaystack;
185 }
186 } while (*++pHaystack == *pNeedle);
187 }
188 cpszHaystack++;
189 }
190
191 return 0;
192 }
193
194
std_memcmp(const void * p1,const void * p2,int length)195 int std_memcmp(const void* p1, const void* p2, int length)
196 {
197 const unsigned char *cpc1 = p1;
198 const unsigned char *cpc2 = p2;
199
200 while (length-- > 0) {
201 int diff = *cpc1++ - *cpc2++;
202
203 if (0 != diff) {
204 return diff;
205 }
206 }
207 return 0;
208 }
209
std_wstrlen(const AECHAR * s)210 int std_wstrlen(const AECHAR* s)
211 {
212 const AECHAR *sEnd = s;
213
214 if (! *sEnd)
215 return 0;
216
217 do {
218 ++sEnd;
219 } while (*sEnd);
220
221 return sEnd - s;
222 }
223
224
std_wstrlcpy(AECHAR * pwcDst,const AECHAR * cpwszSrc,int nDestSize)225 int std_wstrlcpy(AECHAR* pwcDst, const AECHAR* cpwszSrc, int nDestSize)
226 {
227 int nLen = std_wstrlen(cpwszSrc);
228
229 if (0 < nDestSize) {
230 int n;
231
232 n = STD_MIN(nLen, nDestSize - 1);
233 /* call memmove, in case n is larger than 1G */
234 (void)std_memsmove(pwcDst, nDestSize*sizeof(AECHAR),
235 cpwszSrc, ((size_t)n)*sizeof(AECHAR));
236
237 pwcDst[n] = 0;
238 }
239
240 return nLen;
241 }
242
std_wstrlcat(AECHAR * pwcDst,const AECHAR * cpwszSrc,int nDestSize)243 int std_wstrlcat(AECHAR* pwcDst, const AECHAR* cpwszSrc, int nDestSize)
244 {
245 int nLen = 0;
246
247 while ((nLen < nDestSize) && (0 != pwcDst[nLen])) {
248 ++nLen;
249 }
250
251 return nLen + std_wstrlcpy(pwcDst+nLen, cpwszSrc, nDestSize-nLen);
252 }
253
std_strchrend(const char * cpsz,char c)254 char* std_strchrend(const char* cpsz, char c)
255 {
256 while (*cpsz && *cpsz != c) {
257 ++cpsz;
258 }
259 return (char*)cpsz;
260 }
261
std_strchr(const char * cpszSrch,int c)262 char* std_strchr(const char* cpszSrch, int c)
263 {
264 const char *pc = std_strchrend(cpszSrch, (char)c);
265
266 return (*pc == c ? (char*)pc : 0);
267 }
268
std_memstr(const char * cpHaystack,const char * cpszNeedle,int nHaystackLen)269 void* std_memstr(const char* cpHaystack, const char* cpszNeedle,
270 int nHaystackLen)
271 {
272 int nLen = 0;
273
274 /* Handle empty needle string as a special case */
275 if ('\0' == *cpszNeedle ) {
276 return (char*)cpHaystack;
277 }
278
279 /* Find the first character of the needle string in the haystack string */
280 while (nLen < nHaystackLen) {
281 if (cpHaystack[nLen] == *cpszNeedle) {
282 /* check if the rest of the string matches */
283 const char* cpNeedle = cpszNeedle;
284 int nRetIndex = nLen;
285 do {
286 if ('\0' == *++cpNeedle) {
287 /* Found a match */
288 return (void*)(cpHaystack + nRetIndex);
289 }
290 nLen++;
291 } while(cpHaystack[nLen] == *cpNeedle);
292 }
293 else {
294 nLen++;
295 }
296 }
297
298 return 0;
299 }
300
std_memchrend(const void * p,int c,int nLen)301 void* std_memchrend(const void* p, int c, int nLen)
302 {
303 const char* cpc = (const char*)p + nLen;
304 int i = -nLen;
305
306 if (nLen > 0) {
307 do {
308 if (cpc[i] == c) {
309 break;
310 }
311 } while (++i);
312 }
313 return (void*) (cpc + i);
314 }
315
std_memchr(const void * s,int c,int n)316 void* std_memchr(const void* s, int c, int n)
317 {
318 const char *pEnd = (const char*)std_memchrend(s,c,n);
319 int nEnd = pEnd - (const char*)s;
320
321 if (nEnd < n) {
322 return (void*)pEnd;
323 }
324 return 0;
325 }
326
std_memrchr(const void * p,int c,int nLen)327 void* std_memrchr(const void* p, int c, int nLen)
328 {
329 const char* cpc = (const char*)p - 1;
330
331 if (nLen > 0) {
332 do {
333 if (cpc[nLen] == c) {
334 return (void*) (cpc + nLen);
335 }
336 } while (--nLen);
337 }
338
339 return 0;
340 }
341
342
std_strrchr(const char * cpsz,int c)343 char* std_strrchr(const char* cpsz, int c)
344 {
345 return std_memrchr(cpsz, c, std_strlen(cpsz) + 1);
346 }
347
348
std_memrchrbegin(const void * p,int c,int n)349 void* std_memrchrbegin(const void* p, int c, int n)
350 {
351 void *pOut = std_memrchr(p, c, n);
352
353 return (pOut ? pOut : (void*)p);
354 }
355
356
357 // x_scanbytes: internal function; WARNING: nLen must be >0
358 //
359 // cStop = character at which to stop (in addition to cpszChars[...])
360 //
361 // Using a bit mask provides a constant-time check for a terminating
362 // character: 10 instructions for inner loop on ADS12arm9. Initialization
363 // overhead is increased, but this is quickly made up for as searching begins.
364 //
365 //
x_scanbytes(const char * pcBuf,const char * cpszChars,int nLen,unsigned char cStop,boolean bTestEqual)366 static char *x_scanbytes(const char *pcBuf, const char* cpszChars,
367 int nLen, unsigned char cStop, boolean bTestEqual)
368 {
369 int n;
370 unsigned a[8];
371
372 // Initialize bit mask based on the input flag that specifies whether
373 // we are looking for a character that matches "any" or "none"
374 // of the characters in the search string
375
376 #define ENTRY(c) a[((c)&7)] // c's bit lives here
377 #define SHIFT(c) ((c)>>3) // c's bit is shifted by this much
378
379 if (bTestEqual) {
380 std_memset(a, 0, STD_SIZEOF(a));
381 do {
382 ENTRY(cStop) |= (0x80000000U >> SHIFT(cStop));
383 cStop = (unsigned char)*cpszChars++;
384 } while (cStop);
385 }
386 else {
387 std_memset(a, 0xFF, STD_SIZEOF(a));
388
389 while (0 != (cStop = (unsigned char)*cpszChars++)) {
390 ENTRY(cStop) ^= (0x80000000U >> SHIFT(cStop));
391 }
392 }
393
394
395 // Search buffer
396
397 pcBuf += nLen;
398 n = -nLen;
399 do {
400 unsigned char uc = (unsigned char)pcBuf[n];
401 // testing for negative after shift is quicker than comparison
402 if ( (int)(ENTRY(uc) << SHIFT(uc)) < 0) {
403 break;
404 }
405 } while (++n);
406
407 return (char*)(pcBuf+n);
408 }
409
410
std_memchrsend(const void * pBuf,const char * cpszChars,int nLen)411 void* std_memchrsend(const void* pBuf, const char* cpszChars, int nLen)
412 {
413 if (nLen <= 0) {
414 return (void*)pBuf;
415 }
416 if ('\0' == *cpszChars) {
417 return (char*)pBuf + nLen;
418 }
419
420 return x_scanbytes((const char*)pBuf, cpszChars+1, nLen,
421 (unsigned char)*cpszChars, TRUE);
422 }
423
424
std_strchrsend(const char * cpszSrch,const char * cpszChars)425 char* std_strchrsend(const char* cpszSrch, const char* cpszChars)
426 {
427 return x_scanbytes(cpszSrch, cpszChars, MAX_INT32, '\0', TRUE);
428 }
429
430
std_strchrs(const char * cpszSrch,const char * cpszChars)431 char *std_strchrs(const char* cpszSrch, const char* cpszChars)
432 {
433 const char *pc = std_strchrsend(cpszSrch, cpszChars);
434
435 return (*pc ? (char*)pc : 0);
436 }
437
438
std_striends(const char * cpsz,const char * cpszSuffix)439 char* std_striends(const char* cpsz, const char* cpszSuffix)
440 {
441 int nOffset = std_strlen(cpsz) - std_strlen(cpszSuffix);
442
443 if ((0 <= nOffset) &&
444 (0 == std_stricmp(cpsz+nOffset, cpszSuffix))) {
445
446 return (char*)(cpsz+nOffset);
447 }
448
449 return 0;
450 }
451
452
std_strends(const char * cpsz,const char * cpszSuffix)453 char* std_strends(const char* cpsz, const char* cpszSuffix)
454 {
455 int nOffset = std_strlen(cpsz) - std_strlen(cpszSuffix);
456
457 if ((0 <= nOffset) &&
458 (0 == std_strcmp(cpsz+nOffset, cpszSuffix))) {
459
460 return (char*)(cpsz + nOffset);
461 }
462
463 return 0;
464 }
465
std_strbegins(const char * cpsz,const char * cpszPrefix)466 char* std_strbegins(const char* cpsz, const char* cpszPrefix)
467 {
468 for (;;) {
469 if ('\0' == *cpszPrefix) {
470 return (char*)cpsz;
471 }
472
473 if (*cpszPrefix != *cpsz) {
474 return 0;
475 }
476
477 ++cpszPrefix;
478 ++cpsz;
479 }
480 // not reached
481 }
482
std_stribegins(const char * cpsz,const char * cpszPrefix)483 char* std_stribegins(const char* cpsz, const char* cpszPrefix)
484 {
485 for (;;) {
486 if ('\0' == *cpszPrefix) {
487 return (char*)cpsz;
488 }
489
490 if (x_casecmp((unsigned char)*cpszPrefix, (unsigned char)*cpsz)) {
491 return 0;
492 }
493
494 ++cpszPrefix;
495 ++cpsz;
496 }
497 // not reached
498 }
499
std_strcspn(const char * cpszSrch,const char * cpszChars)500 int std_strcspn(const char* cpszSrch, const char* cpszChars)
501 {
502 const char *pc = x_scanbytes(cpszSrch, cpszChars, MAX_INT32, '\0', TRUE);
503
504 return (pc - cpszSrch);
505 }
506
std_strspn(const char * cpszSrch,const char * cpszChars)507 int std_strspn(const char* cpszSrch, const char* cpszChars)
508 {
509 const char *pc = x_scanbytes(cpszSrch, cpszChars, MAX_INT32, '\0', FALSE);
510
511 return (pc - cpszSrch);
512 }
513
std_wstrncmp(const AECHAR * s1,const AECHAR * s2,int nLen)514 int std_wstrncmp(const AECHAR* s1, const AECHAR* s2, int nLen)
515 {
516 if (nLen > 0) {
517 int i;
518
519 s1 += nLen;
520 s2 += nLen;
521 i = -nLen;
522 do {
523 AECHAR c1 = s1[i];
524 AECHAR c2 = s2[i];
525 int diff = c1 - c2;
526
527 if (diff) {
528 return diff;
529 }
530
531 if ('\0' == c1) {
532 break;
533 }
534 } while (++i);
535 }
536
537 return 0;
538 }
539
std_wstrcmp(const AECHAR * s1,const AECHAR * s2)540 int std_wstrcmp(const AECHAR* s1, const AECHAR* s2)
541 {
542 return std_wstrncmp(s1, s2, MAX_INT32);
543 }
544
std_wstrchr(const AECHAR * cpwszText,AECHAR ch)545 AECHAR* std_wstrchr(const AECHAR* cpwszText, AECHAR ch)
546 {
547 for (; ; cpwszText++) {
548 AECHAR chn = *cpwszText;
549
550 if (chn == ch) {
551 return (AECHAR *)cpwszText;
552 }
553 else if ( chn == (AECHAR)0 ) {
554 return 0;
555 }
556 }
557 }
558
std_wstrrchr(const AECHAR * cpwszText,AECHAR ch)559 AECHAR* std_wstrrchr(const AECHAR* cpwszText, AECHAR ch)
560 {
561 const AECHAR* p = 0;
562
563 do {
564 if (*cpwszText == ch) {
565 p = cpwszText;
566 }
567 } while (*cpwszText++ != (AECHAR)0);
568
569 return (AECHAR*)p;
570 }
571