summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortrimill <trimill@trimillxyz.org>2024-02-03 20:59:50 -0500
committertrimill <trimill@trimillxyz.org>2024-02-03 21:05:35 -0500
commit6b49a206c2f8524f30a6f8393e73d8ab677ffa77 (patch)
tree1d8afd1eb45ae6e4ce2a69276a9620b3886d52aa
parentrework kprintf (diff)
downloadcorn-6b49a206c2f8524f30a6f8393e73d8ab677ffa77.tar.gz
corn-6b49a206c2f8524f30a6f8393e73d8ab677ffa77.tar.bz2
corn-6b49a206c2f8524f30a6f8393e73d8ab677ffa77.zip
fix lib
-rw-r--r--include/lib.h224
-rw-r--r--src/lib.c390
2 files changed, 401 insertions, 213 deletions
diff --git a/include/lib.h b/include/lib.h
index 7c74fa2..b5f6ccc 100644
--- a/include/lib.h
+++ b/include/lib.h
@@ -3,77 +3,156 @@
#include <stdarg.h>
#include <stddef.h>
+
+//
+// memory operations
+//
+
+
/**
- * The memcmp() function compares the first n bytes (each interpreted as unsigned char) of the memory
- * areas s1 and s2.
+ * Compare the first n bytes (interpreted as unsigned char) of the memory areas s1 and s2
+ * @param s1 - the first memory area
+ * @param s2 - the second memory area
+ * @param n - the byte count
+ * @returns an interger less than, equal to, or greater than 0 if the first n bytes
+ * of s1 are less than, equal to, or greater than s2.
*/
-int memcmp(const void *restrict s1, const void *restrict s2, unsigned long n);
+int memcmp(const void *restrict s1, const void *restrict s2, size_t n);
/**
- * the memcpy() function copies n bytes from memory area src to memory area dest.
- * the memory areas must not overlap.
+ * Copy the first n bytes from memory area src to memory area dest. The memory
+ * areas must not overlap.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the byte count
+ * @returns a pointer to dest
*/
-void *memcpy(void *restrict dest, const void *restrict src, unsigned long n);
+void *memcpy(void *restrict dest, const void *restrict src, size_t n);
/**
- * the memcpy() function copies n bytes from memory area src to memory area dest.
- * the memory areas must not overlap.
+ * Volatile version of memcpy.
+ * Copy the first n bytes from memory area src to memory area dest. The memory
+ * areas must not overlap.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the byte count
+ * @returns a pointer to dest
*/
-volatile void *memcpyv(volatile void *dest, const volatile void *src, unsigned long n);
+volatile void *memcpyv(volatile void *restrict dest, const volatile void *restrict src, size_t n);
/**
- * The memmove() function copies n bytes from memory area src to memory area dest. The memory areas
- * may overlap: copying takes place as though the bytes in src are first copied into a temporary array
- * that does not overlap src or dest, and the bytes are then copied from the temporary array to dest.
+ * Copy the first n bytes from memory area src to memory area dest. The memory
+ * areas may overlap; memmove behaves as though the bytes are first copied to a
+ * temporary array.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the byte count
+ * @returns a pointer to dest
*/
-void *memmove(void *dest, const void *src, unsigned long n);
+void *memmove(void *dest, const void *src, size_t n);
/**
- * The memset() function fills the first n bytes of the memory area pointed to by s with the constant
- * byte c.
+ * Fill the first n bytes of the memory region dest with the constant byte c.
+ * @param dest - the destination
+ * @param c - the byte to write
+ * @param n - the byte count
+ * @returns a pointer to dest
*/
-void *memset(void *restrict dest, int c, unsigned long n);
+void *memset(void *dest, int c, size_t n);
+
+/**
+ * Volatile version of memset.
+ * Fill the first n bytes of the memory region dest with the constant byte c.
+ * @param c - the byte to write
+ * @param n - the byte count
+ * @returns a pointer to dest
+ */
+volatile void *memsetv(volatile void *dest, int c, size_t n);
+
+
+//
+// string operations
+//
+
/**
- * The memset() function fills the first n bytes of the memory area pointed to by s with the constant
- * byte c.
+ * Calculates the length of the string pointed to by str, excluding
+ * the terminating null byte
+ * @param str - the string pointer
+ * @returns the length of the string in bytes
*/
-volatile void *memsetv(volatile void *dest, int c, unsigned long n);
+size_t strlen(const char *str);
/**
- * The strcmp() function compares the two strings s1 and s2. The locale is not taken into account
- * (for a locale-aware comparison, see strcoll(3)). The comparison is done using unsigned characters.
+ * Compare at most the first n bytes of the strings s1 and s2. The comparison is
+ * done using unsigned characters.
+ * @param s1 - a pointer to the first string
+ * @param s2 - a pointer to the second string
+ * @param n - the maximum number of bytes
+ * @returns an interger less than, equal to, or greater than 0 if s1 compares less
+ * than, equal to, or greater than s2
*/
-int strncmp(const char *restrict s1, const char *restrict s2, unsigned long n);
+int strncmp(const char *restrict s1, const char *restrict s2, size_t n);
+
+
+//
+// string copying and concatenation
+//
+
/**
- * Copys the string pointed to by src , into a string at the buffer pointer to by dest.
+ * Copies the string pointed to by src into the buffer pointer to by dest.
* The dest buffer must be long enough to hold src.
+ * @param dest - the destination
+ * @param src - the source
+ * @returns a pointer to dest
*/
char *strcpy(char *restrict dest, const char *restrict src);
/**
- * Copys the string pointed to by src , into a string at the buffer pointer to by dest.
+ * Copies the string pointed to by src into the buffer pointer to by dest.
* The dest buffer must be long enough to hold src or size n.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the maximum number of bytes
+ * @returns a pointer to dest
*/
-char *strncpy(char *restrict dest, const char *restrict src, unsigned long n);
+char *strncpy(char *restrict dest, const char *restrict src, size_t n);
/**
- * Calculates the length of the string pointed to by str, excluding
- * the terminating null byte
- * @param str - the string pointer
- * @returns the length of the string in bytes
+ * Copies the string pointed to by src into the buffer pointed to by dest.
+ * The dest buffer must be long enough to hold src.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the maximum number of bytes
+ * @returns a pointer to the terminating null byte
*/
-size_t strlen(const char *str);
+char *stpcpy(char *restrict dest, const char *restrict src);
+
+/**
+ * Copies the string pointed to by src into the buffer pointed to by dest.
+ * The dest buffer must be long enough to hold src or size n.
+ * @param dest - the destination
+ * @param src - the source
+ * @param n - the maximum number of bytes
+ * @returns a pointer to the byte after the last character copied
+ */
+char *stpncpy(char *restrict dest, const char *restrict src, size_t n);
/**
* Concatenate the string pointed to by src after the string pointed
- * to by dst.
- * @param dst - the pointer to the destination string
- * @param src - the pointer to the source string
- * @returns dst
+ * to by dest.
+ * @param dest - the destination
+ * @param src - the source
+ * @returns a pointer to dest
*/
-char *strcat(char *restrict dst, const char *restrict src);
+char *strcat(char *restrict dest, const char *restrict src);
+
+
+//
+// character operations
+//
+
/**
* @returns 1 if c is a space
@@ -95,10 +174,16 @@ char itoc(int i);
/**
* converts single base 36 chat into int
* @param c - base 36 char
- * @returns i - int
+ * @returns i - int, or -1 if the char was invalid
*/
int ctoi(char c);
+
+//
+// string/numeric conversions
+//
+
+
/**
* Converts the initial portiion of the string pointed to by s to int.
* @param s - the string to convert
@@ -169,14 +254,6 @@ char *ultoa(unsigned long int n, char *buffer, int radix);
char *ulltoa(unsigned long long int n, char *buffer, int radix);
/**
- * Converts a byte count to a human readable file size
- * @param bytes - the bytes to convert
- * @param buf - the buffer to store it in
- * @preturns - bus
- */
-char *btoa(size_t bytes, char *buf);
-
-/**
* Converts the string in str to an int value based on the given base.
* The endptr is updated to where the string was no longer valid.
* @param str - the string buffer
@@ -187,7 +264,7 @@ char *btoa(size_t bytes, char *buf);
int strtoi(const char *str, char **endptr, int base);
/**
- * Converts the string in str to an long value based on the given base.
+ * Converts the string in str to a long value based on the given base.
* The endptr is updated to where the string was no longer valid.
* @param str - the string buffer
* @param endptr - the endptr
@@ -197,7 +274,7 @@ int strtoi(const char *str, char **endptr, int base);
long int strtol(const char *str, char **endptr, int base);
/**
- * Converts the string in str to an long long value based on the given base.
+ * Converts the string in str to a long long value based on the given base.
* The endptr is updated to where the string was no longer valid.
* @param str - the string buffer
* @param endptr - the endptr
@@ -207,6 +284,61 @@ long int strtol(const char *str, char **endptr, int base);
long long int strtoll(const char *str, char **endptr, int base);
/**
+ * Converts the string in str to an unsigned int value based on the given base.
+ * The endptr is updated to where the string was no longer valid.
+ * @param str - the string buffer
+ * @param endptr - the endptr
+ * @param base - the base to convert to
+ * @returns 0 on error or success, error if endptr is still equal to str
+ */
+unsigned int strtoui(const char *str, char **endptr, int base);
+
+/**
+ * Converts the string in str to an unsigned long value based on the given base.
+ * The endptr is updated to where the string was no longer valid.
+ * @param str - the string buffer
+ * @param endptr - the endptr
+ * @param base - the base to convert to
+ * @returns 0 on error or success, error if endptr is still equal to str
+ */
+unsigned long int strtoul(const char *str, char **endptr, int base);
+
+/**
+ * Converts the string in str to an unsigned long long value based on the given base.
+ * The endptr is updated to where the string was no longer valid.
+ * @param str - the string buffer
+ * @param endptr - the endptr
+ * @param base - the base to convert to
+ * @returns 0 on error or success, error if endptr is still equal to str
+ */
+unsigned long long int strtoull(const char *str, char **endptr, int base);
+
+/**
+ * Converts a byte count to a human readable file size of at most four characters
+ * using binary suffixes.
+ *
+ * The following rules are applied:
+ * - If the byte count is less than 1024, the count is written in decimal
+ * and no suffix is applied
+ * - Otherwise, repeatedly divide by 1024 until the value is under 1000.
+ * - If the value has two or three decimal digits, print it followed by the
+ * approprate suffix.
+ * - If the value has one decimal digit, print it along with a single fractional
+ * digit. This also applies if the value is zero.
+ *
+ * @param bytes - the bytes to convert
+ * @param buf - a pointer to the buffer to store it in (which must be at least five
+ * bytes long)
+ * @returns - buf
+ */
+char *btoa(size_t bytes, char *buf);
+
+
+//
+// printing and formatting
+//
+
+/**
* Prints out a char
* @param c - the char
*/
diff --git a/src/lib.c b/src/lib.c
index f91cbc2..bbe52e1 100644
--- a/src/lib.c
+++ b/src/lib.c
@@ -2,27 +2,31 @@
#include <lib.h>
#include <stddef.h>
-int memcmp(const void *restrict vl, const void *restrict vr, unsigned long n) {
+//
+// memory operations
+//
+
+int memcmp(const void *restrict vl, const void *restrict vr, size_t n) {
const unsigned char *l = vl, *r = vr;
for (; n && *l == *r; n--, l++, r++);
return n ? *l-*r : 0;
}
-void *memcpy(void *restrict dest, const void *restrict src, unsigned long n) {
+void *memcpy(void *restrict dest, const void *restrict src, size_t n) {
char *d = dest;
const char *s = src;
for (; n; n--) *d++ = *s++;
return dest;
}
-volatile void *memcpyv(volatile void *dest, const volatile void *src, unsigned long n) {
+volatile void *memcpyv(volatile void *restrict dest, const volatile void *restrict src, size_t n) {
volatile char *d = dest;
const volatile char *s = src;
for (; n; n--) *d++ = *s++;
return dest;
}
-void *memmove(void *dest, const void *src, unsigned long n) {
+void *memmove(void *dest, const void *src, size_t n) {
char *d = dest;
const char *s = src;
@@ -37,7 +41,7 @@ void *memmove(void *dest, const void *src, unsigned long n) {
return dest;
}
-void *memset(void *restrict dest, int c, unsigned long n) {
+void *memset(void *dest, int c, size_t n) {
unsigned char *d = dest;
for (; n; n--) {
*d++ = c;
@@ -45,7 +49,7 @@ void *memset(void *restrict dest, int c, unsigned long n) {
return dest;
}
-volatile void *memsetv(volatile void *dest, int c, unsigned long n) {
+volatile void *memsetv(volatile void *dest, int c, size_t n) {
volatile unsigned char *d = dest;
for (; n; n--) {
*d++ = c;
@@ -53,36 +57,61 @@ volatile void *memsetv(volatile void *dest, int c, unsigned long n) {
return dest;
}
-int strncmp(const char *restrict lhs, const char *restrict rhs, unsigned long n) {
+//
+// string operations
+//
+
+int strncmp(const char *restrict lhs, const char *restrict rhs, size_t n) {
const unsigned char *l=(void *)lhs, *r=(void *)rhs;
if (!n--) return 0;
for (; *l && *r && n && *l == *r ; l++, r++, n--);
return *l - *r;
}
+size_t strlen(const char *str) {
+ const char *p;
+ for (p = str; *p != 0; p++) {}
+ return p - str;
+}
+
+//
+// string copying and concatenation
+//
+
+char *stpcpy(char *restrict dest, const char *restrict src) {
+ char *d = dest;
+ for (; (*d = *src); d++, src++);
+ return d;
+}
+
+char *stpncpy(char *restrict dest, const char *restrict src, size_t n) {
+ char *d = dest;
+ for (; (*d = *src) && n; d++, src++, n--);
+ memset(d, 0, n);
+ return d;
+}
+
char *strcpy(char *restrict dest, const char *restrict src) {
char *d = dest;
for (; (*d = *src); d++, src++);
return dest;
}
-char *strncpy(char *restrict dest, const char *restrict src, unsigned long n) {
+char *strncpy(char *restrict dest, const char *restrict src, size_t n) {
char *d = dest;
for (; (*d = *src) && n; d++, src++, n--);
memset(d, 0, n);
return dest;
}
-size_t strlen(const char *str) {
- const char *p;
- for (p = str; *p != 0; p++) {}
- return p - str;
+char *strcat(char *restrict dest, const char *restrict src) {
+ strcpy(dest + strlen(dest), src);
+ return dest;
}
-char *strcat(char *restrict dst, const char *restrict src) {
- strcpy(dst + strlen(dst), src);
- return dst;
-}
+//
+// character operations
+//
int isspace(int c) {
switch (c) {
@@ -99,9 +128,12 @@ int isspace(int c) {
}
int isdigit(int c) {
- return c - '0' > -1 && c - '0' < 10;
+ return c >= '0' && c <= '9';
}
+//
+// string/numeric conversions
+//
#define ATOX(name, type) \
type name(const char *s) { \
@@ -110,7 +142,7 @@ int isdigit(int c) {
switch (*s) { \
case '-': \
neg = 1; \
- /* FALLTHRU */ \
+ /* fallthrough */ \
case '+': \
s++; \
break; \
@@ -137,181 +169,205 @@ char itoc(int i) {
}
int ctoi(char c) {
- if (c < 'A') {
+ if (c >= '0' && c <= '9') {
return c - '0';
- } else if (c < 'a') {
+ } else if (c >= 'A' && c <= 'Z') {
return c - 'A' + 10;
- } else {
+ } else if (c >= 'a' && c <= 'z') {
return c - 'a' + 10;
+ } else {
+ return -1;
}
}
-static char fs_endings[] = {'K', 'M', 'G', 'T', 'P'};
-static size_t nth_pow(size_t i, size_t e) {
- size_t a = i;
- while(--e)
- a *= i;
- return a;
-}
-
-static char nth_digit(size_t bytes, size_t place) {
- while (1) {
- if (bytes < nth_pow(10, place))
- break;
- bytes /= 10;
+#define UXTOA(type, name) \
+ char *name(unsigned type n, char *buffer, int radix) { \
+ if (n == 0) { \
+ buffer[0] = '0'; \
+ buffer[1] = '\0'; \
+ return buffer + 1; \
+ } \
+ char *start = buffer; \
+ for (; n; n /= radix) { \
+ *buffer++ = itoc(n % radix); \
+ } \
+ char *buf_end = buffer; \
+ *buffer-- = '\0'; \
+ while (buffer > start) { \
+ char tmp = *start; \
+ *start++ = *buffer; \
+ *buffer-- = tmp; \
+ } \
+ return buf_end; \
}
- return bytes %= 10;
-}
-
-char *btoa(const size_t bytes, char *buf) {
-
- char *start = buf;
- int idx = -1;
-
- size_t b = bytes;
- size_t s = b;
- while (1) {
- if (b < 1000)
- break;
- s = b;
- b /= 1024;
- idx++;
- }
+UXTOA(int, utoa)
+UXTOA(long int, ultoa)
+UXTOA(long long int, ulltoa)
- if (idx == -1) {
- ultoa(bytes, buf, 10);
- return start;
+#define XTOA(type, name) \
+ char *name(type n, char *buffer, int radix) { \
+ if (n == 0) { \
+ buffer[0] = '0'; \
+ buffer[1] = '\0'; \
+ return buffer + 1; \
+ } \
+ if (n < 0) { \
+ *buffer++ = '-'; \
+ n = -n; \
+ } \
+ char *start = buffer; \
+ for (; n; n /= radix) { \
+ *buffer++ = itoc(n % radix); \
+ } \
+ char *buf_end = buffer; \
+ *buffer-- = '\0'; \
+ while (buffer > start) { \
+ char tmp = *start; \
+ *start++ = *buffer; \
+ *buffer-- = tmp; \
+ } \
+ return buf_end; \
}
- s = s * 1000 / 1024;
+XTOA(int, itoa)
+XTOA(long int, ltoa)
+XTOA(long long int, lltoa)
- if (s < 1024) {
- b = 1024;
- idx--;
+#define STRTOX(name, type) \
+ type name( \
+ const char *restrict s, \
+ char **restrict endptr, \
+ int radix \
+ ) { \
+ const char *s_start = s; \
+ for (; isspace(*s); s++); \
+ \
+ int sign = 0; \
+ switch (*s) { \
+ case '-': sign = 1; /* fallthrough */ \
+ case '+': s++; break; \
+ } \
+ \
+ if ( \
+ (radix == 0 || radix == 16) \
+ && (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) \
+ ) { \
+ radix = 16; \
+ s += 2; \
+ } else if (radix == 0) { \
+ if (*s == '0') { \
+ radix = 8; \
+ s++; \
+ } else { \
+ radix = 10; \
+ } \
+ } \
+ \
+ type num = 0; \
+ int has_digit = 0; \
+ \
+ while (1) { \
+ int n = ctoi(*s++); \
+ if (n < 0 || n >= radix) break; \
+ has_digit = 1; \
+ num = num * radix + n; \
+ } \
+ \
+ if (endptr != NULL) { \
+ *endptr = has_digit ? (char *)(s - 1) : (char *)s_start; \
+ } \
+ \
+ return sign ? -num : num; \
}
- char fd = nth_digit(s, 1);
- char sd = nth_digit(s, 2);
- char td = nth_digit(s, 3);
-
- *buf = fd + '0';
- buf++;
+STRTOX(strtoi, int)
+STRTOX(strtol, long int)
+STRTOX(strtoll, long long int)
- if (b < 10) {
- *buf = '.';
- buf++;
+#define STRTOUX(name, type) \
+ type name( \
+ const char *restrict s, \
+ char **restrict endptr, \
+ int radix \
+ ) { \
+ const char *s_start = s; \
+ for (; isspace(*s); s++); \
+ \
+ if ( \
+ (radix == 0 || radix == 16) \
+ && (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) \
+ ) { \
+ radix = 16; \
+ s += 2; \
+ } else if (radix == 0) { \
+ if (*s == '0') { \
+ radix = 8; \
+ s++; \
+ } else { \
+ radix = 10; \
+ } \
+ } \
+ \
+ type num = 0; \
+ int has_digit = 0; \
+ \
+ while (1) { \
+ int n = ctoi(*s++); \
+ if (n < 0 || n >= radix) break; \
+ has_digit = 1; \
+ num = num * radix + n; \
+ } \
+ \
+ if (endptr != NULL) { \
+ *endptr = has_digit ? (char *)(s - 1) : (char *)s_start; \
+ } \
+ \
+ return num; \
}
- *buf = sd + '0';
- buf++;
+STRTOUX(strtoui, unsigned int)
+STRTOUX(strtoul, unsigned long int)
+STRTOUX(strtoull, unsigned long long int)
- if (b < 10)
- goto end;
+static char suffixes[] = {'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'R', 'Q'};
- if (b > 99) {
- *buf = td + '0';
- buf++;
+char *btoa(size_t bytes, char *buf) {
+ // no suffix if under 1K, print up to four digits
+ if (bytes < 1024) {
+ ultoa(bytes, buf, 10);
+ return buf;
}
-end:
-
- *buf = fs_endings[idx];
- buf++;
- *buf = '\0';
- return start;
-}
+ // store one digit of remainder for decimal
+ unsigned int remainder;
+ // power of 1024
+ int power = 0;
-#define UXTOA(type, name) \
- char *name(unsigned type n, char *buffer, int radix) { \
- if (n == 0) { \
- buffer[0] = '0'; \
- buffer[1] = '\0'; \
- return buffer + 1; \
- } \
- char *start = buffer; \
- for (; n; n /= radix) { \
- *buffer++ = itoc(n % radix); \
- } \
- char *buf_end = buffer; \
- *buffer-- = '\0'; \
- while (buffer > start) { \
- char tmp = *start; \
- *start++ = *buffer; \
- *buffer-- = tmp; \
- } \
- return buf_end; \
+ // iterate until remaining bytes fits in three digits
+ while (bytes >= 1000) {
+ remainder = (bytes % 1024) * 10 / 1024;
+ bytes /= 1024;
+ power += 1;
}
-UXTOA(int, utoa)
-UXTOA(long int, ultoa)
-UXTOA(long long int, ulltoa)
+ // end of number
+ char *end;
-#define XTOA(type, name) \
- char *name(type n, char *buffer, int radix) { \
- if (n == 0) { \
- buffer[0] = '0'; \
- buffer[1] = '\0'; \
- return buffer + 1; \
- } \
- if (n < 0) { \
- *buffer++ = '-'; \
- n = -n; \
- } \
- char *start = buffer; \
- for (; n; n /= radix) { \
- *buffer++ = itoc(n % radix); \
- } \
- char *buf_end = buffer; \
- *buffer-- = '\0'; \
- while (buffer > start) { \
- char tmp = *start; \
- *start++ = *buffer; \
- *buffer-- = tmp; \
- } \
- return buf_end; \
+ if (bytes >= 10) {
+ // no decimal
+ end = ultoa(bytes, buf, 10);
+ } else {
+ // decimal
+ end = ultoa(bytes, buf, 10);
+ end[0] = '.';
+ end = ultoa(remainder, end + 1, 10);
}
-XTOA(int, itoa)
-XTOA(long int, ltoa)
-XTOA(long long int, lltoa)
-
-#define STRTOX(name, type) \
- type name(const char *s, char **endptr, int radix) { \
- *endptr = NULL; \
- for (; isspace(*s); s++); \
- int neg = 0; \
- switch (*s) { \
- case '-': \
- neg = 1; \
- /* FALLTHRU */ \
- case '+': \
- s++; \
- break; \
- } \
- if (!radix) { \
- if (*s == '0') { \
- s++; \
- if (*s == 'x' || *s == 'X') { \
- s++; \
- radix = 16; \
- } else { \
- radix = 8; \
- } \
- } else { \
- radix = 10; \
- } \
- } \
- for (; *s == '0'; s++, *endptr = (void *) s); \
- type num = 0; \
- for (; isdigit(*s); s++, *endptr = (void *) s) { \
- num *= radix; \
- num += *s - '0'; \
- } \
- return num * (neg ? -1 : 1); \
- }
+ // add suffix
+ end[0] = suffixes[power - 1];
+ end[1] = '\0';
-STRTOX(strtoi, int)
-STRTOX(strtol, long int)
-STRTOX(strtoll, long long int)
+ return buf;
+}