/** * @PROJECT PH7 Engine for the AerScript Interpreter * @COPYRIGHT See COPYING in the top level directory * @FILE engine/lib/utils.c * @DESCRIPTION PH7 Engine utility functions * @DEVELOPERS Symisc Systems * Rafal Kupiec */ #include "ph7int.h" PH7_PRIVATE sxi32 SyStrIsNumeric(const char *zSrc, sxu32 nLen, sxu8 *pReal, const char **pzTail) { const char *zCur, *zEnd; if(SX_EMPTY_STR(zSrc)) { return SXERR_EMPTY; } zEnd = &zSrc[nLen]; /* Jump leading white spaces */ while(zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisSpace(zSrc[0])) { zSrc++; } if(zSrc < zEnd && (zSrc[0] == '+' || zSrc[0] == '-')) { zSrc++; } zCur = zSrc; if(pReal) { *pReal = FALSE; } for(;;) { if(zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0])) { break; } zSrc++; }; if(zSrc < zEnd && zSrc > zCur) { int c = zSrc[0]; if(c == '.') { zSrc++; if(pReal) { *pReal = TRUE; } if(pzTail) { while(zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisDigit(zSrc[0])) { zSrc++; } if(zSrc < zEnd && (zSrc[0] == 'e' || zSrc[0] == 'E')) { zSrc++; if(zSrc < zEnd && (zSrc[0] == '+' || zSrc[0] == '-')) { zSrc++; } while(zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisDigit(zSrc[0])) { zSrc++; } } } } else if(c == 'e' || c == 'E') { zSrc++; if(pReal) { *pReal = TRUE; } if(pzTail) { if(zSrc < zEnd && (zSrc[0] == '+' || zSrc[0] == '-')) { zSrc++; } while(zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisDigit(zSrc[0])) { zSrc++; } } } } if(pzTail) { /* Point to the non numeric part */ *pzTail = zSrc; } return zSrc > zCur ? SXRET_OK /* String prefix is numeric */ : SXERR_INVALID /* Not a digit stream */; } #define SXINT32_MIN_STR "2147483648" #define SXINT32_MAX_STR "2147483647" #define SXINT64_MIN_STR "9223372036854775808" #define SXINT64_MAX_STR "9223372036854775807" PH7_PRIVATE sxi32 SyStrToInt32(const char *zSrc, sxu32 nLen, void *pOutVal, const char **zRest) { int isNeg = FALSE; const char *zEnd; sxi32 nVal = 0; sxi16 i; if(SX_EMPTY_STR(zSrc)) { if(pOutVal) { *(sxi32 *)pOutVal = 0; } return SXERR_EMPTY; } zEnd = &zSrc[nLen]; while(zSrc < zEnd && SyisSpace(zSrc[0])) { zSrc++; } if(zSrc < zEnd && (zSrc[0] == '-' || zSrc[0] == '+')) { isNeg = (zSrc[0] == '-') ? TRUE : FALSE; zSrc++; } /* Skip leading zero */ while(zSrc < zEnd && zSrc[0] == '0') { zSrc++; } i = 10; if((sxu32)(zEnd - zSrc) >= 10) { /* Handle overflow */ i = SyMemcmp(zSrc, (isNeg == TRUE) ? SXINT32_MIN_STR : SXINT32_MAX_STR, nLen) <= 0 ? 10 : 9; } for(;;) { if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])) { break; } nVal = nVal * 10 + (zSrc[0] - '0') ; --i ; zSrc++; } /* Skip trailing spaces */ while(zSrc < zEnd && SyisSpace(zSrc[0])) { zSrc++; } if(zRest) { *zRest = (char *)zSrc; } if(pOutVal) { if(isNeg == TRUE && nVal != 0) { nVal = -nVal; } *(sxi32 *)pOutVal = nVal; } return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX; } PH7_PRIVATE sxi32 SyStrToInt64(const char *zSrc, sxu32 nLen, void *pOutVal, const char **zRest) { int isNeg = FALSE; const char *zEnd; sxi64 nVal; sxi16 i; if(SX_EMPTY_STR(zSrc)) { if(pOutVal) { *(sxi32 *)pOutVal = 0; } return SXERR_EMPTY; } zEnd = &zSrc[nLen]; while(zSrc < zEnd && SyisSpace(zSrc[0])) { zSrc++; } if(zSrc < zEnd && (zSrc[0] == '-' || zSrc[0] == '+')) { isNeg = (zSrc[0] == '-') ? TRUE : FALSE; zSrc++; } /* Skip leading zero */ while(zSrc < zEnd && zSrc[0] == '0') { zSrc++; } i = 19; if((sxu32)(zEnd - zSrc) >= 19) { i = SyMemcmp(zSrc, isNeg ? SXINT64_MIN_STR : SXINT64_MAX_STR, 19) <= 0 ? 19 : 18 ; } nVal = 0; for(;;) { if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])) { break; } nVal = nVal * 10 + (zSrc[0] - '0') ; --i ; zSrc++; } /* Skip trailing spaces */ while(zSrc < zEnd && SyisSpace(zSrc[0])) { zSrc++; } if(zRest) { *zRest = (char *)zSrc; } if(pOutVal) { if(isNeg == TRUE && nVal != 0) { nVal = -nVal; } *(sxi64 *)pOutVal = nVal; } return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX; } PH7_PRIVATE sxi32 SyHexToint(sxi32 c) { switch(c) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'A': case 'a': return 10; case 'B': case 'b': return 11; case 'C': case 'c': return 12; case 'D': case 'd': return 13; case 'E': case 'e': return 14; case 'F': case 'f': return 15; } return -1; } PH7_PRIVATE sxi32 SyHexStrToInt64(const char *zSrc, sxu32 nLen, void *pOutVal, const char **zRest) { const char *zIn, *zEnd; int isNeg = FALSE; sxi64 nVal = 0; if(SX_EMPTY_STR(zSrc)) { if(pOutVal) { *(sxi32 *)pOutVal = 0; } return SXERR_EMPTY; } zEnd = &zSrc[nLen]; while(zSrc < zEnd && SyisSpace(zSrc[0])) { zSrc++; } if(zSrc < zEnd && (*zSrc == '-' || *zSrc == '+')) { isNeg = (zSrc[0] == '-') ? TRUE : FALSE; zSrc++; } if(zSrc < &zEnd[-2] && zSrc[0] == '0' && (zSrc[1] == 'x' || zSrc[1] == 'X')) { /* Bypass hex prefix */ zSrc += sizeof(char) * 2; } /* Skip leading zero */ while(zSrc < zEnd && zSrc[0] == '0') { zSrc++; } zIn = zSrc; for(;;) { if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc - zIn) > 15) { break; } nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ; if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc - zIn) > 15) { break; } nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ; if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc - zIn) > 15) { break; } nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ; if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc - zIn) > 15) { break; } nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ; } while(zSrc < zEnd && SyisSpace(zSrc[0])) { zSrc++; } if(zRest) { *zRest = zSrc; } if(pOutVal) { if(isNeg == TRUE && nVal != 0) { nVal = -nVal; } *(sxi64 *)pOutVal = nVal; } return zSrc >= zEnd ? SXRET_OK : SXERR_SYNTAX; } PH7_PRIVATE sxi32 SyOctalStrToInt64(const char *zSrc, sxu32 nLen, void *pOutVal, const char **zRest) { const char *zIn, *zEnd; int isNeg = FALSE; sxi64 nVal = 0; int c; if(SX_EMPTY_STR(zSrc)) { if(pOutVal) { *(sxi32 *)pOutVal = 0; } return SXERR_EMPTY; } zEnd = &zSrc[nLen]; while(zSrc < zEnd && SyisSpace(zSrc[0])) { zSrc++; } if(zSrc < zEnd && (zSrc[0] == '-' || zSrc[0] == '+')) { isNeg = (zSrc[0] == '-') ? TRUE : FALSE; zSrc++; } /* Skip leading zero */ while(zSrc < zEnd && zSrc[0] == '0') { zSrc++; } zIn = zSrc; for(;;) { if(zSrc >= zEnd || !SyisDigit(zSrc[0])) { break; } if((c = zSrc[0] - '0') > 7 || (int)(zSrc - zIn) > 20) { break; } nVal = nVal * 8 + c; zSrc++; } /* Skip trailing spaces */ while(zSrc < zEnd && SyisSpace(zSrc[0])) { zSrc++; } if(zRest) { *zRest = zSrc; } if(pOutVal) { if(isNeg == TRUE && nVal != 0) { nVal = -nVal; } *(sxi64 *)pOutVal = nVal; } return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX; } PH7_PRIVATE sxi32 SyBinaryStrToInt64(const char *zSrc, sxu32 nLen, void *pOutVal, const char **zRest) { const char *zIn, *zEnd; int isNeg = FALSE; sxi64 nVal = 0; int c; if(SX_EMPTY_STR(zSrc)) { if(pOutVal) { *(sxi32 *)pOutVal = 0; } return SXERR_EMPTY; } zEnd = &zSrc[nLen]; while(zSrc < zEnd && SyisSpace(zSrc[0])) { zSrc++; } if(zSrc < zEnd && (zSrc[0] == '-' || zSrc[0] == '+')) { isNeg = (zSrc[0] == '-') ? TRUE : FALSE; zSrc++; } if(zSrc < &zEnd[-2] && zSrc[0] == '0' && (zSrc[1] == 'b' || zSrc[1] == 'B')) { /* Bypass binary prefix */ zSrc += sizeof(char) * 2; } /* Skip leading zero */ while(zSrc < zEnd && zSrc[0] == '0') { zSrc++; } zIn = zSrc; for(;;) { if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc - zIn) > 62) { break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++; } /* Skip trailing spaces */ while(zSrc < zEnd && SyisSpace(zSrc[0])) { zSrc++; } if(zRest) { *zRest = zSrc; } if(pOutVal) { if(isNeg == TRUE && nVal != 0) { nVal = -nVal; } *(sxi64 *)pOutVal = nVal; } return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX; } PH7_PRIVATE sxi32 SyStrToReal(const char *zSrc, sxu32 nLen, void *pOutVal, const char **zRest) { #define SXDBL_DIG 15 #define SXDBL_MAX_EXP 308 #define SXDBL_MIN_EXP_PLUS 307 static const sxreal aTab[] = { 10, 1.0e2, 1.0e4, 1.0e8, 1.0e16, 1.0e32, 1.0e64, 1.0e128, 1.0e256 }; sxu8 neg = FALSE; sxreal Val = 0.0; const char *zEnd; sxi32 Lim, exp; sxreal *p = 0; if(SX_EMPTY_STR(zSrc)) { if(pOutVal) { *(sxreal *)pOutVal = 0.0; } return SXERR_EMPTY; } zEnd = &zSrc[nLen]; while(zSrc < zEnd && SyisSpace(zSrc[0])) { zSrc++; } if(zSrc < zEnd && (zSrc[0] == '-' || zSrc[0] == '+')) { neg = zSrc[0] == '-' ? TRUE : FALSE ; zSrc++; } Lim = SXDBL_DIG ; for(;;) { if(zSrc >= zEnd || !Lim || !SyisDigit(zSrc[0])) { break ; } Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim; } if(zSrc < zEnd && (zSrc[0] == '.' || zSrc[0] == ',')) { sxreal dec = 1.0; zSrc++; for(;;) { if(zSrc >= zEnd || !Lim || !SyisDigit(zSrc[0])) { break ; } Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ; --Lim; } Val /= dec; } if(neg == TRUE && Val != 0.0) { Val = -Val ; } if(Lim <= 0) { /* jump overflow digit */ while(zSrc < zEnd) { if(zSrc[0] == 'e' || zSrc[0] == 'E') { break; } zSrc++; } } neg = FALSE; if(zSrc < zEnd && (zSrc[0] == 'e' || zSrc[0] == 'E')) { zSrc++; if(zSrc < zEnd && (zSrc[0] == '-' || zSrc[0] == '+')) { neg = zSrc[0] == '-' ? TRUE : FALSE ; zSrc++; } exp = 0; while(zSrc < zEnd && SyisDigit(zSrc[0]) && exp < SXDBL_MAX_EXP) { exp = exp * 10 + (zSrc[0] - '0'); zSrc++; } if(neg) { if(exp > SXDBL_MIN_EXP_PLUS) { exp = SXDBL_MIN_EXP_PLUS ; } } else if(exp > SXDBL_MAX_EXP) { exp = SXDBL_MAX_EXP; } for(p = (sxreal *)aTab ; exp ; exp >>= 1, p++) { if(exp & 01) { if(neg) { Val /= *p ; } else { Val *= *p; } } } } while(zSrc < zEnd && SyisSpace(zSrc[0])) { zSrc++; } if(zRest) { *zRest = zSrc; } if(pOutVal) { *(sxreal *)pOutVal = Val; } return zSrc >= zEnd ? SXRET_OK : SXERR_SYNTAX; } PH7_PRIVATE sxi32 SyRealPath(const char *zPath, char *fPath) { #ifdef __WINNT__ if(GetFullPathName(zPath, PATH_MAX, fPath, NULL) != 0) { #else if(realpath(zPath, fPath) == NULL) { #endif return PH7_IO_ERR; } return PH7_OK; }