summaryrefslogtreecommitdiff
path: root/src/std.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/std.c')
-rw-r--r--src/std.c570
1 files changed, 570 insertions, 0 deletions
diff --git a/src/std.c b/src/std.c
new file mode 100644
index 0000000..d369d99
--- /dev/null
+++ b/src/std.c
@@ -0,0 +1,570 @@
+/**
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+=======================================================================
+
+FILE: std.c
+
+SERVICES: apiOne std lib string stuff
+
+=======================================================================
+*/
+
+//
+// someday, drop this #include, implement our own memmove()
+//
+#include <stddef.h>
+#include "AEEstd.h"
+#include "version.h"
+
+int std_getversion(char *pcDst, int nDestSize)
+{
+ return std_strlcpy(pcDst, VERSION_STRING, nDestSize);
+}
+
+
+char std_tolower(char c)
+{
+ if ((c >= 'A') && (c <= 'Z')) {
+ c |= 32;
+ }
+ return c;
+}
+
+char std_toupper(char c)
+{
+ if ((c >= 'a') && (c <= 'z')) {
+ c &= ~32;
+ }
+ return c;
+}
+
+
+static __inline int x_casecmp(unsigned char c1, unsigned char c2)
+{
+ int diff = c1 - c2;
+ if (c1 >= 'A' && c1 <= 'Z') {
+ diff += 32;
+ }
+ if (c2 >= 'A' && c2 <= 'Z') {
+ diff -= 32;
+ }
+ return diff;
+}
+
+
+int std_strncmp(const char* s1, const char* s2, int n)
+{
+ if (n > 0) {
+ int i = 0;
+
+ do {
+ unsigned char c1 = (unsigned char)s1[i];
+ unsigned char c2 = (unsigned char)s2[i];
+ int diff = c1 - c2;
+
+ if (diff) {
+ return diff;
+ }
+
+ if ('\0' == c1) {
+ break;
+ }
+ i++;
+ } while (i < n);
+ }
+
+ return 0;
+}
+
+int std_strcmp(const char* s1, const char* s2)
+{
+ return std_strncmp(s1, s2, MAX_INT32);
+}
+
+int std_strnicmp(const char* s1, const char* s2, int n)
+{
+ if (n > 0) {
+ int i = -n;
+
+ s1 += n;
+ s2 += n;
+
+ do {
+ unsigned char c1 = (unsigned char)s1[i];
+ unsigned char c2 = (unsigned char)s2[i];
+
+ int diff = x_casecmp(c1,c2);
+ if (diff) {
+ return diff;
+ }
+ if ('\0' == c1) {
+ break;
+ }
+ } while (++i);
+ }
+ return 0;
+}
+
+int std_stricmp(const char* s1, const char* s2)
+{
+ return std_strnicmp(s1, s2, MAX_INT32);
+}
+
+int std_strlcpy(char* pcDst, const char* cpszSrc, int nDestSize)
+{
+ int nLen = std_strlen(cpszSrc);
+
+ if (0 < nDestSize) {
+ int n;
+
+ n = STD_MIN(nLen, nDestSize - 1);
+ (void)std_memmove(pcDst, cpszSrc, n);
+
+ pcDst[n] = 0;
+ }
+
+ return nLen;
+}
+
+int std_strlcat(char* pcDst, const char* cpszSrc, int nDestSize)
+{
+ int nLen = 0;
+
+ while ((nLen < nDestSize) && (0 != pcDst[nLen])) {
+ ++nLen;
+ }
+
+ return nLen + std_strlcpy(pcDst+nLen, cpszSrc, nDestSize-nLen);
+}
+
+char* std_strstr(const char* cpszHaystack, const char* cpszNeedle)
+{
+ /* Check the empty needle string as a special case */
+ if ('\0' == *cpszNeedle ) {
+ return (char*)cpszHaystack;
+ }
+
+ while ('\0' != *cpszHaystack) {
+ /* Find the first character of the needle string in the haystack string */
+ if (*cpszHaystack == *cpszNeedle) {
+ /* check if the rest of the string matches */
+ const char* pHaystack = cpszHaystack;
+ const char* pNeedle = cpszNeedle;
+ do {
+ if ('\0' == *++pNeedle) {
+ /* Found a match */
+ return (char*)cpszHaystack;
+ }
+ } while (*++pHaystack == *pNeedle);
+ }
+ cpszHaystack++;
+ }
+
+ return 0;
+}
+
+
+int std_memcmp(const void* p1, const void* p2, int length)
+{
+ const unsigned char *cpc1 = p1;
+ const unsigned char *cpc2 = p2;
+
+ while (length-- > 0) {
+ int diff = *cpc1++ - *cpc2++;
+
+ if (0 != diff) {
+ return diff;
+ }
+ }
+ return 0;
+}
+
+int std_wstrlen(const AECHAR* s)
+{
+ const AECHAR *sEnd = s;
+
+ if (! *sEnd)
+ return 0;
+
+ do {
+ ++sEnd;
+ } while (*sEnd);
+
+ return sEnd - s;
+}
+
+
+int std_wstrlcpy(AECHAR* pwcDst, const AECHAR* cpwszSrc, int nDestSize)
+{
+ int nLen = std_wstrlen(cpwszSrc);
+
+ if (0 < nDestSize) {
+ int n;
+
+ n = STD_MIN(nLen, nDestSize - 1);
+ /* call memmove, in case n is larger than 1G */
+ (void)std_memsmove(pwcDst, nDestSize*sizeof(AECHAR),
+ cpwszSrc, ((size_t)n)*sizeof(AECHAR));
+
+ pwcDst[n] = 0;
+ }
+
+ return nLen;
+}
+
+int std_wstrlcat(AECHAR* pwcDst, const AECHAR* cpwszSrc, int nDestSize)
+{
+ int nLen = 0;
+
+ while ((nLen < nDestSize) && (0 != pwcDst[nLen])) {
+ ++nLen;
+ }
+
+ return nLen + std_wstrlcpy(pwcDst+nLen, cpwszSrc, nDestSize-nLen);
+}
+
+char* std_strchrend(const char* cpsz, char c)
+{
+ while (*cpsz && *cpsz != c) {
+ ++cpsz;
+ }
+ return (char*)cpsz;
+}
+
+char* std_strchr(const char* cpszSrch, int c)
+{
+ const char *pc = std_strchrend(cpszSrch, (char)c);
+
+ return (*pc == c ? (char*)pc : 0);
+}
+
+void* std_memstr(const char* cpHaystack, const char* cpszNeedle,
+ int nHaystackLen)
+{
+ int nLen = 0;
+
+ /* Handle empty needle string as a special case */
+ if ('\0' == *cpszNeedle ) {
+ return (char*)cpHaystack;
+ }
+
+ /* Find the first character of the needle string in the haystack string */
+ while (nLen < nHaystackLen) {
+ if (cpHaystack[nLen] == *cpszNeedle) {
+ /* check if the rest of the string matches */
+ const char* cpNeedle = cpszNeedle;
+ int nRetIndex = nLen;
+ do {
+ if ('\0' == *++cpNeedle) {
+ /* Found a match */
+ return (void*)(cpHaystack + nRetIndex);
+ }
+ nLen++;
+ } while(cpHaystack[nLen] == *cpNeedle);
+ }
+ else {
+ nLen++;
+ }
+ }
+
+ return 0;
+}
+
+void* std_memchrend(const void* p, int c, int nLen)
+{
+ const char* cpc = (const char*)p + nLen;
+ int i = -nLen;
+
+ if (nLen > 0) {
+ do {
+ if (cpc[i] == c) {
+ break;
+ }
+ } while (++i);
+ }
+ return (void*) (cpc + i);
+}
+
+void* std_memchr(const void* s, int c, int n)
+{
+ const char *pEnd = (const char*)std_memchrend(s,c,n);
+ int nEnd = pEnd - (const char*)s;
+
+ if (nEnd < n) {
+ return (void*)pEnd;
+ }
+ return 0;
+}
+
+void* std_memrchr(const void* p, int c, int nLen)
+{
+ const char* cpc = (const char*)p - 1;
+
+ if (nLen > 0) {
+ do {
+ if (cpc[nLen] == c) {
+ return (void*) (cpc + nLen);
+ }
+ } while (--nLen);
+ }
+
+ return 0;
+}
+
+
+char* std_strrchr(const char* cpsz, int c)
+{
+ return std_memrchr(cpsz, c, std_strlen(cpsz) + 1);
+}
+
+
+void* std_memrchrbegin(const void* p, int c, int n)
+{
+ void *pOut = std_memrchr(p, c, n);
+
+ return (pOut ? pOut : (void*)p);
+}
+
+
+// x_scanbytes: internal function; WARNING: nLen must be >0
+//
+// cStop = character at which to stop (in addition to cpszChars[...])
+//
+// Using a bit mask provides a constant-time check for a terminating
+// character: 10 instructions for inner loop on ADS12arm9. Initialization
+// overhead is increased, but this is quickly made up for as searching begins.
+//
+//
+static char *x_scanbytes(const char *pcBuf, const char* cpszChars,
+ int nLen, unsigned char cStop, boolean bTestEqual)
+{
+ int n;
+ unsigned a[8];
+
+ // Initialize bit mask based on the input flag that specifies whether
+ // we are looking for a character that matches "any" or "none"
+ // of the characters in the search string
+
+ #define ENTRY(c) a[((c)&7)] // c's bit lives here
+ #define SHIFT(c) ((c)>>3) // c's bit is shifted by this much
+
+ if (bTestEqual) {
+ std_memset(a, 0, STD_SIZEOF(a));
+ do {
+ ENTRY(cStop) |= (0x80000000U >> SHIFT(cStop));
+ cStop = (unsigned char)*cpszChars++;
+ } while (cStop);
+ }
+ else {
+ std_memset(a, 0xFF, STD_SIZEOF(a));
+
+ while (0 != (cStop = (unsigned char)*cpszChars++)) {
+ ENTRY(cStop) ^= (0x80000000U >> SHIFT(cStop));
+ }
+ }
+
+
+ // Search buffer
+
+ pcBuf += nLen;
+ n = -nLen;
+ do {
+ unsigned char uc = (unsigned char)pcBuf[n];
+ // testing for negative after shift is quicker than comparison
+ if ( (int)(ENTRY(uc) << SHIFT(uc)) < 0) {
+ break;
+ }
+ } while (++n);
+
+ return (char*)(pcBuf+n);
+}
+
+
+void* std_memchrsend(const void* pBuf, const char* cpszChars, int nLen)
+{
+ if (nLen <= 0) {
+ return (void*)pBuf;
+ }
+ if ('\0' == *cpszChars) {
+ return (char*)pBuf + nLen;
+ }
+
+ return x_scanbytes((const char*)pBuf, cpszChars+1, nLen,
+ (unsigned char)*cpszChars, TRUE);
+}
+
+
+char* std_strchrsend(const char* cpszSrch, const char* cpszChars)
+{
+ return x_scanbytes(cpszSrch, cpszChars, MAX_INT32, '\0', TRUE);
+}
+
+
+char *std_strchrs(const char* cpszSrch, const char* cpszChars)
+{
+ const char *pc = std_strchrsend(cpszSrch, cpszChars);
+
+ return (*pc ? (char*)pc : 0);
+}
+
+
+char* std_striends(const char* cpsz, const char* cpszSuffix)
+{
+ int nOffset = std_strlen(cpsz) - std_strlen(cpszSuffix);
+
+ if ((0 <= nOffset) &&
+ (0 == std_stricmp(cpsz+nOffset, cpszSuffix))) {
+
+ return (char*)(cpsz+nOffset);
+ }
+
+ return 0;
+}
+
+
+char* std_strends(const char* cpsz, const char* cpszSuffix)
+{
+ int nOffset = std_strlen(cpsz) - std_strlen(cpszSuffix);
+
+ if ((0 <= nOffset) &&
+ (0 == std_strcmp(cpsz+nOffset, cpszSuffix))) {
+
+ return (char*)(cpsz + nOffset);
+ }
+
+ return 0;
+}
+
+char* std_strbegins(const char* cpsz, const char* cpszPrefix)
+{
+ for (;;) {
+ if ('\0' == *cpszPrefix) {
+ return (char*)cpsz;
+ }
+
+ if (*cpszPrefix != *cpsz) {
+ return 0;
+ }
+
+ ++cpszPrefix;
+ ++cpsz;
+ }
+ // not reached
+}
+
+char* std_stribegins(const char* cpsz, const char* cpszPrefix)
+{
+ for (;;) {
+ if ('\0' == *cpszPrefix) {
+ return (char*)cpsz;
+ }
+
+ if (x_casecmp((unsigned char)*cpszPrefix, (unsigned char)*cpsz)) {
+ return 0;
+ }
+
+ ++cpszPrefix;
+ ++cpsz;
+ }
+ // not reached
+}
+
+int std_strcspn(const char* cpszSrch, const char* cpszChars)
+{
+ const char *pc = x_scanbytes(cpszSrch, cpszChars, MAX_INT32, '\0', TRUE);
+
+ return (pc - cpszSrch);
+}
+
+int std_strspn(const char* cpszSrch, const char* cpszChars)
+{
+ const char *pc = x_scanbytes(cpszSrch, cpszChars, MAX_INT32, '\0', FALSE);
+
+ return (pc - cpszSrch);
+}
+
+int std_wstrncmp(const AECHAR* s1, const AECHAR* s2, int nLen)
+{
+ if (nLen > 0) {
+ int i;
+
+ s1 += nLen;
+ s2 += nLen;
+ i = -nLen;
+ do {
+ AECHAR c1 = s1[i];
+ AECHAR c2 = s2[i];
+ int diff = c1 - c2;
+
+ if (diff) {
+ return diff;
+ }
+
+ if ('\0' == c1) {
+ break;
+ }
+ } while (++i);
+ }
+
+ return 0;
+}
+
+int std_wstrcmp(const AECHAR* s1, const AECHAR* s2)
+{
+ return std_wstrncmp(s1, s2, MAX_INT32);
+}
+
+AECHAR* std_wstrchr(const AECHAR* cpwszText, AECHAR ch)
+{
+ for (; ; cpwszText++) {
+ AECHAR chn = *cpwszText;
+
+ if (chn == ch) {
+ return (AECHAR *)cpwszText;
+ }
+ else if ( chn == (AECHAR)0 ) {
+ return 0;
+ }
+ }
+}
+
+AECHAR* std_wstrrchr(const AECHAR* cpwszText, AECHAR ch)
+{
+ const AECHAR* p = 0;
+
+ do {
+ if (*cpwszText == ch) {
+ p = cpwszText;
+ }
+ } while (*cpwszText++ != (AECHAR)0);
+
+ return (AECHAR*)p;
+}