| #include "ficl.h" |
| #include <limits.h> |
| |
| /* |
| * a l i g n P t r |
| * Aligns the given pointer to FICL_ALIGN address units. |
| * Returns the aligned pointer value. |
| */ |
| void * |
| ficlAlignPointer(void *ptr) |
| { |
| #if FICL_PLATFORM_ALIGNMENT > 1 |
| intptr_t p = (intptr_t)ptr; |
| |
| if (p & (FICL_PLATFORM_ALIGNMENT - 1)) |
| ptr = (void *)((p & ~(FICL_PLATFORM_ALIGNMENT - 1)) + |
| FICL_PLATFORM_ALIGNMENT); |
| #endif |
| return (ptr); |
| } |
| |
| /* |
| * s t r r e v |
| */ |
| char * |
| ficlStringReverse(char *string) |
| { |
| int i = strlen(string); |
| char *p1 = string; /* first char of string */ |
| char *p2 = string + i - 1; /* last non-NULL char of string */ |
| char c; |
| |
| if (i > 1) { |
| while (p1 < p2) { |
| c = *p2; |
| *p2 = *p1; |
| *p1 = c; |
| p1++; p2--; |
| } |
| } |
| |
| return (string); |
| } |
| |
| /* |
| * d i g i t _ t o _ c h a r |
| */ |
| static char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
| |
| char |
| ficlDigitToCharacter(int value) |
| { |
| return (digits[value]); |
| } |
| |
| /* |
| * i s P o w e r O f T w o |
| * Tests whether supplied argument is an integer power of 2 (2**n) |
| * where 32 > n > 1, and returns n if so. Otherwise returns zero. |
| */ |
| int |
| ficlIsPowerOfTwo(ficlUnsigned u) |
| { |
| int i = 1; |
| ficlUnsigned t = 2; |
| |
| for (; ((t <= u) && (t != 0)); i++, t <<= 1) { |
| if (u == t) |
| return (i); |
| } |
| |
| return (0); |
| } |
| |
| /* |
| * l t o a |
| */ |
| char * |
| ficlLtoa(ficlInteger value, char *string, int radix) |
| { |
| char *cp = string; |
| int sign = ((radix == 10) && (value < 0)); |
| int pwr; |
| |
| FICL_ASSERT(NULL, radix > 1); |
| FICL_ASSERT(NULL, radix < 37); |
| FICL_ASSERT(NULL, string); |
| |
| pwr = ficlIsPowerOfTwo((ficlUnsigned)radix); |
| |
| if (sign) |
| value = -value; |
| |
| if (value == 0) |
| *cp++ = '0'; |
| else if (pwr != 0) { |
| ficlUnsigned v = (ficlUnsigned) value; |
| ficlUnsigned mask = ~(ULONG_MAX << pwr); |
| while (v) { |
| *cp++ = digits[v & mask]; |
| v >>= pwr; |
| } |
| } else { |
| ficl2UnsignedQR result; |
| ficl2Unsigned v; |
| FICL_UNSIGNED_TO_2UNSIGNED((ficlUnsigned)value, v); |
| while (FICL_2UNSIGNED_NOT_ZERO(v)) { |
| result = ficl2UnsignedDivide(v, (ficlUnsigned)radix); |
| *cp++ = digits[result.remainder]; |
| v = result.quotient; |
| } |
| } |
| |
| if (sign) |
| *cp++ = '-'; |
| |
| *cp++ = '\0'; |
| |
| return (ficlStringReverse(string)); |
| } |
| |
| /* |
| * u l t o a |
| */ |
| char * |
| ficlUltoa(ficlUnsigned value, char *string, int radix) |
| { |
| char *cp = string; |
| ficl2Unsigned ud; |
| ficl2UnsignedQR result; |
| |
| FICL_ASSERT(NULL, radix > 1); |
| FICL_ASSERT(NULL, radix < 37); |
| FICL_ASSERT(NULL, string); |
| |
| if (value == 0) |
| *cp++ = '0'; |
| else { |
| FICL_UNSIGNED_TO_2UNSIGNED(value, ud); |
| while (FICL_2UNSIGNED_NOT_ZERO(ud)) { |
| result = ficl2UnsignedDivide(ud, (ficlUnsigned)radix); |
| ud = result.quotient; |
| *cp++ = digits[result.remainder]; |
| } |
| } |
| |
| *cp++ = '\0'; |
| |
| return (ficlStringReverse(string)); |
| } |
| |
| /* |
| * c a s e F o l d |
| * Case folds a NULL terminated string in place. All characters |
| * get converted to lower case. |
| */ |
| char * |
| ficlStringCaseFold(char *cp) |
| { |
| char *oldCp = cp; |
| |
| while (*cp) { |
| if (isupper((unsigned char)*cp)) |
| *cp = (char)tolower((unsigned char)*cp); |
| cp++; |
| } |
| |
| return (oldCp); |
| } |
| |
| /* |
| * s t r i n c m p |
| * (jws) simplified the code a bit in hopes of appeasing Purify |
| */ |
| int |
| ficlStrincmp(char *cp1, char *cp2, ficlUnsigned count) |
| { |
| int i = 0; |
| |
| for (; 0 < count; ++cp1, ++cp2, --count) { |
| i = tolower((unsigned char)*cp1) - tolower((unsigned char)*cp2); |
| if (i != 0) |
| return (i); |
| else if (*cp1 == '\0') |
| return (0); |
| } |
| return (0); |
| } |
| |
| /* |
| * s k i p S p a c e |
| * Given a string pointer, returns a pointer to the first non-space |
| * char of the string, or to the NULL terminator if no such char found. |
| * If the pointer reaches "end" first, stop there. Pass NULL to |
| * suppress this behavior. |
| */ |
| char * |
| ficlStringSkipSpace(char *cp, char *end) |
| { |
| FICL_ASSERT(NULL, cp); |
| |
| while ((cp != end) && isspace((unsigned char)*cp)) |
| cp++; |
| |
| return (cp); |
| } |
| |
| void |
| ficlCompatibilityTextOutCallback(ficlCallback *callback, char *text, |
| ficlCompatibilityOutputFunction outputFunction) |
| { |
| char buffer[256]; |
| char *bufferStop = buffer + sizeof (buffer) - 1; |
| |
| if (text == NULL) { |
| outputFunction(callback->vm, NULL, 0 /* false */); |
| return; |
| } |
| |
| while (*text) { |
| int newline = 0 /* false */; |
| char *trace = buffer; |
| while ((*text) && (trace < bufferStop)) { |
| switch (*text) { |
| /* throw away \r */ |
| case '\r': |
| text++; |
| continue; |
| case '\n': |
| text++; |
| newline = !0 /* true */; |
| break; |
| default: |
| *trace++ = *text++; |
| break; |
| } |
| } |
| |
| *trace = 0; |
| (outputFunction)(callback->vm, buffer, newline); |
| } |
| } |