mirror of
https://git.musl-libc.org/git/musl
synced 2025-03-31 23:13:08 +03:00

the difference of pointers is a signed type ptrdiff_t; if it is only 32-bit, left-shifting it by 30 bits produces undefined behavior. cast the difference to an appropriate unsigned type, uint32_t, before shifting to avoid this. the a64l function is specified to return a signed 32-bit result in type long. as noted in the bug report by Ed Schouten, converting implicitly from uint32_t only produces the desired result when long is a 32-bit type. since the computation has to be done in unsigned arithmetic to avoid overflow, simply cast the result to int32_t. further, POSIX leaves the behavior on invalid input unspecified but not undefined, so we should not take the difference between the potentially-null result of strchr and the base pointer without first checking the result. the simplest behavior is just returning the partial conversion already performed in this case, so do that.
30 lines
499 B
C
30 lines
499 B
C
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
|
|
static const char digits[] =
|
|
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
|
|
long a64l(const char *s)
|
|
{
|
|
int e;
|
|
uint32_t x = 0;
|
|
for (e=0; e<36 && *s; e+=6, s++) {
|
|
const char *d = strchr(digits, *s);
|
|
if (!d) break;
|
|
x |= (uint32_t)(d-digits)<<e;
|
|
}
|
|
return (int32_t)x;
|
|
}
|
|
|
|
char *l64a(long x0)
|
|
{
|
|
static char s[7];
|
|
char *p;
|
|
uint32_t x = x0;
|
|
for (p=s; x; p++, x>>=6)
|
|
*p = digits[x&63];
|
|
*p = 0;
|
|
return s;
|
|
}
|