From 6b49a206c2f8524f30a6f8393e73d8ab677ffa77 Mon Sep 17 00:00:00 2001 From: trimill Date: Sat, 3 Feb 2024 20:59:50 -0500 Subject: [PATCH] fix lib --- include/lib.h | 234 +++++++++++++++++++++------- src/lib.c | 412 ++++++++++++++++++++++++++++---------------------- 2 files changed, 417 insertions(+), 229 deletions(-) diff --git a/include/lib.h b/include/lib.h index 7c74fa2..b5f6ccc 100644 --- a/include/lib.h +++ b/include/lib.h @@ -3,60 +3,77 @@ #include #include -/** - * The memcmp() function compares the first n bytes (each interpreted as unsigned char) of the memory - * areas s1 and s2. - */ -int memcmp(const void *restrict s1, const void *restrict s2, unsigned long n); + +// +// memory operations +// + /** - * the memcpy() function copies n bytes from memory area src to memory area dest. - * the memory areas must not overlap. + * 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. */ -void *memcpy(void *restrict dest, const void *restrict src, 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 */ -volatile void *memcpyv(volatile void *dest, const volatile void *src, unsigned long n); +void *memcpy(void *restrict dest, const 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. + * 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 */ -void *memmove(void *dest, const void *src, unsigned long n); +volatile void *memcpyv(volatile void *restrict dest, const volatile void *restrict 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. + * 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 *memset(void *restrict dest, int c, 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 */ -volatile void *memsetv(volatile void *dest, int c, unsigned long n); +void *memset(void *dest, int c, size_t n); /** - * 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. + * 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 */ -int strncmp(const char *restrict s1, const char *restrict s2, unsigned long n); +volatile void *memsetv(volatile void *dest, int c, size_t n); -/** - * Copys the string pointed to by src , into a string at the buffer pointer to by dest. - * The dest buffer must be long enough to hold src. - */ -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. - * The dest buffer must be long enough to hold src or size n. - */ -char *strncpy(char *restrict dest, const char *restrict src, unsigned long n); +// +// string operations +// + /** * Calculates the length of the string pointed to by str, excluding @@ -67,13 +84,75 @@ char *strncpy(char *restrict dest, const char *restrict src, unsigned long n); size_t strlen(const char *str); /** - * 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 + * 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 */ -char *strcat(char *restrict dst, const char *restrict src); +int strncmp(const char *restrict s1, const char *restrict s2, size_t n); + + +// +// string copying and concatenation +// + + +/** + * 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); + +/** + * 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, size_t n); + +/** + * 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 + */ +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 dest. + * @param dest - the destination + * @param src - the source + * @returns a pointer to dest + */ +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 @@ -168,14 +253,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. @@ -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 @@ -206,6 +283,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 #include -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,37 +57,62 @@ 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; } -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 *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 dst, const char *restrict src) { - strcpy(dst + strlen(dst), src); - return dst; +// +// 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, size_t n) { + char *d = dest; + for (; (*d = *src) && n; d++, src++, n--); + memset(d, 0, n); + return dest; +} + +char *strcat(char *restrict dest, const char *restrict src) { + strcpy(dest + strlen(dest), src); + return dest; +} + +// +// character operations +// + int isspace(int c) { switch (c) { case ' ': @@ -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; - } - 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++; - } - - if (idx == -1) { - ultoa(bytes, buf, 10); - return start; - } - - s = s * 1000 / 1024; - - if (s < 1024) { - b = 1024; - idx--; - } - - char fd = nth_digit(s, 1); - char sd = nth_digit(s, 2); - char td = nth_digit(s, 3); - - *buf = fd + '0'; - buf++; - - if (b < 10) { - *buf = '.'; - buf++; - } - - *buf = sd + '0'; - buf++; - - if (b < 10) - goto end; - - if (b > 99) { - *buf = td + '0'; - buf++; - } - -end: - - *buf = fs_endings[idx]; - buf++; - *buf = '\0'; - return start; -} - -#define UXTOA(type, name) \ +#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; \ + 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; \ } UXTOA(int, utoa) UXTOA(long int, ultoa) UXTOA(long long int, ulltoa) -#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; \ +#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; \ } 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); \ +#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; \ } STRTOX(strtoi, int) STRTOX(strtol, long int) STRTOX(strtoll, long long int) + +#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; \ + } + +STRTOUX(strtoui, unsigned int) +STRTOUX(strtoul, unsigned long int) +STRTOUX(strtoull, unsigned long long int) + +static char suffixes[] = {'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'R', 'Q'}; + +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; + } + + // store one digit of remainder for decimal + unsigned int remainder; + // power of 1024 + int power = 0; + + // iterate until remaining bytes fits in three digits + while (bytes >= 1000) { + remainder = (bytes % 1024) * 10 / 1024; + bytes /= 1024; + power += 1; + } + + // end of number + char *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); + } + + // add suffix + end[0] = suffixes[power - 1]; + end[1] = '\0'; + + return buf; +}