324 lines
6.8 KiB
C
324 lines
6.8 KiB
C
/* string.c
|
|
* (c) 2002 Mikulas Patocka
|
|
* This file is a part of the Links program, released under GPL.
|
|
*/
|
|
|
|
#include "links.h"
|
|
|
|
int snprint(unsigned char *s, int n, my_uintptr_t num)
|
|
{
|
|
my_uintptr_t q = 1;
|
|
while (q <= num / 10) q *= 10;
|
|
while (n-- > 1 && q) {
|
|
*(s++) = (unsigned char)(num / q + '0');
|
|
num %= q;
|
|
#ifdef __DECC_VER
|
|
do_not_optimize_here(&q); /* compiler bug */
|
|
#endif
|
|
q /= 10;
|
|
}
|
|
*s = 0;
|
|
return !!q;
|
|
}
|
|
|
|
int snzprint(unsigned char *s, int n, off_t num)
|
|
{
|
|
off_t q = 1;
|
|
if (n > 1 && num < 0) *(s++) = '-', num = -num, n--;
|
|
while (q <= num / 10) q *= 10;
|
|
while (n-- > 1 && q) {
|
|
*(s++) = (unsigned char)(num / q + '0');
|
|
num %= q;
|
|
#ifdef __DECC_VER
|
|
do_not_optimize_here(&q); /* compiler bug */
|
|
#endif
|
|
q /= 10;
|
|
}
|
|
*s = 0;
|
|
return !!q;
|
|
}
|
|
|
|
void add_to_strn(unsigned char **s, unsigned char *a)
|
|
{
|
|
unsigned char *p;
|
|
size_t l1 = strlen(cast_const_char *s), l2 = strlen(cast_const_char a);
|
|
if (((l1 | l2) | (l1 + l2 + 1)) > MAXINT) overalloc();
|
|
p = (unsigned char *)mem_realloc(*s, l1 + l2 + 1);
|
|
strcat(cast_char p, cast_const_char a);
|
|
*s = p;
|
|
}
|
|
|
|
void extend_str(unsigned char **s, int n)
|
|
{
|
|
size_t l = strlen(cast_const_char *s);
|
|
if (((l | n) | (l + n + 1)) > MAXINT) overalloc();
|
|
*s = (unsigned char *)mem_realloc(*s, l + n + 1);
|
|
}
|
|
|
|
void add_bytes_to_str(unsigned char **s, int *l, unsigned char *a, size_t ll)
|
|
{
|
|
unsigned char *p;
|
|
size_t old_length;
|
|
size_t new_length;
|
|
size_t x;
|
|
|
|
if (!ll)
|
|
return;
|
|
|
|
p = *s;
|
|
old_length = (unsigned)*l;
|
|
if (ll + old_length >= (unsigned)MAXINT / 2 || ll + old_length < ll) overalloc();
|
|
new_length = old_length + ll;
|
|
*l = (int)new_length;
|
|
x = old_length ^ new_length;
|
|
if (x >= old_length) {
|
|
/* Need to realloc */
|
|
#ifdef HAVE___BUILTIN_CLZ
|
|
#if !( \
|
|
defined(__tune_i386__) || \
|
|
defined(__tune_i486__) || \
|
|
defined(__tune_i586__) || \
|
|
defined(__tune_k6__) || \
|
|
defined(__tune_lakemont__) || \
|
|
(defined(__alpha__) && !defined(__alpha_cix__)) || \
|
|
(defined(__mips) && __mips < 32) || \
|
|
(defined(__ARM_ARCH) && __ARM_ARCH < 5) || \
|
|
(defined(__sparc__) && (!defined(__VIS__) || __VIS__ < 0x300)) ||\
|
|
defined(__hppa) || \
|
|
defined(__riscv) || \
|
|
defined(__sh__))
|
|
if (!(sizeof(unsigned) & (sizeof(unsigned) - 1))) {
|
|
new_length = 2U << ((sizeof(unsigned) * 8 - 1)
|
|
#ifdef __ICC
|
|
-
|
|
#else
|
|
^
|
|
#endif
|
|
__builtin_clz(new_length));
|
|
} else
|
|
#endif
|
|
#endif
|
|
{
|
|
new_length |= new_length >> 1;
|
|
new_length |= new_length >> 2;
|
|
new_length |= new_length >> 4;
|
|
new_length |= new_length >> 8;
|
|
new_length |= new_length >> 16;
|
|
new_length++;
|
|
}
|
|
p = (unsigned char *)mem_realloc(p, new_length);
|
|
*s = p;
|
|
}
|
|
p[*l] = 0;
|
|
memcpy(p + old_length, a, ll);
|
|
}
|
|
|
|
void add_to_str(unsigned char **s, int *l, unsigned char *a)
|
|
{
|
|
add_bytes_to_str(s, l, a, strlen(cast_const_char a));
|
|
}
|
|
|
|
void add_chr_to_str(unsigned char **s, int *l, unsigned char a)
|
|
{
|
|
add_bytes_to_str(s, l, &a, 1);
|
|
}
|
|
|
|
void add_unsigned_long_num_to_str(unsigned char **s, int *l, my_uintptr_t n)
|
|
{
|
|
unsigned char a[64];
|
|
snprint(a, 64, n);
|
|
add_to_str(s, l, a);
|
|
}
|
|
|
|
void add_num_to_str(unsigned char **s, int *l, off_t n)
|
|
{
|
|
unsigned char a[64];
|
|
if (n >= 0 && n < 1000) {
|
|
unsigned sn = (unsigned)n;
|
|
unsigned char *p = a;
|
|
if (sn >= 100) {
|
|
*p++ = '0' + sn / 100;
|
|
sn %= 100;
|
|
goto d10;
|
|
}
|
|
if (sn >= 10) {
|
|
d10:
|
|
*p++ = '0' + sn / 10;
|
|
sn %= 10;
|
|
}
|
|
*p++ = '0' + sn;
|
|
add_bytes_to_str(s, l, a, p - a);
|
|
} else {
|
|
snzprint(a, 64, n);
|
|
add_to_str(s, l, a);
|
|
}
|
|
}
|
|
|
|
void add_knum_to_str(unsigned char **s, int *l, off_t n)
|
|
{
|
|
unsigned char a[13];
|
|
if (n && n / (1024 * 1024) * (1024 * 1024) == n) snzprint(a, 12, n / (1024 * 1024)), a[strlen(cast_const_char a) + 1] = 0, a[strlen(cast_const_char a)] = 'M';
|
|
else if (n && n / 1024 * 1024 == n) snzprint(a, 12, n / 1024), a[strlen(cast_const_char a) + 1] = 0, a[strlen(cast_const_char a)] = 'k';
|
|
else snzprint(a, 13, n);
|
|
add_to_str(s, l, a);
|
|
}
|
|
|
|
long strtolx(unsigned char *c, unsigned char **end)
|
|
{
|
|
char *end_c;
|
|
long l;
|
|
if (c[0] == '0' && upcase(c[1]) == 'X' && c[2]) l = strtol(cast_const_char(c + 2), &end_c, 16);
|
|
else l = strtol(cast_const_char c, &end_c, 10);
|
|
*end = cast_uchar end_c;
|
|
if (upcase(**end) == 'K') {
|
|
(*end)++;
|
|
if (l < -MAXINT / 1024) return -MAXINT;
|
|
if (l > MAXINT / 1024) return MAXINT;
|
|
return l * 1024;
|
|
}
|
|
if (upcase(**end) == 'M') {
|
|
(*end)++;
|
|
if (l < -MAXINT / (1024 * 1024)) return -MAXINT;
|
|
if (l > MAXINT / (1024 * 1024)) return MAXINT;
|
|
return l * (1024 * 1024);
|
|
}
|
|
return l;
|
|
}
|
|
|
|
my_strtoll_t my_strtoll(unsigned char *string, unsigned char **end)
|
|
{
|
|
char *end_c;
|
|
my_strtoll_t f;
|
|
errno = 0;
|
|
#if defined(HAVE_STRTOLL)
|
|
f = strtoll(cast_const_char string, &end_c, 10);
|
|
#elif defined(HAVE_STRTOQ)
|
|
f = strtoq(cast_const_char string, &end_c, 10);
|
|
#elif defined(HAVE_STRTOIMAX)
|
|
f = strtoimax(cast_const_char string, &end_c, 10);
|
|
#else
|
|
f = strtol(cast_const_char string, &end_c, 10);
|
|
#endif
|
|
if (end)
|
|
*end = cast_uchar end_c;
|
|
if (f < 0 || errno) return -1;
|
|
return f;
|
|
}
|
|
|
|
/* Copies at most dst_size chars into dst. Ensures null termination of dst. */
|
|
void safe_strncpy(unsigned char *dst, const unsigned char *src, size_t dst_size)
|
|
{
|
|
dst[dst_size - 1] = 0;
|
|
strncpy(cast_char dst, cast_const_char src, dst_size - 1);
|
|
}
|
|
|
|
#ifdef JS
|
|
/* deletes all nonprintable characters from string */
|
|
void skip_nonprintable(unsigned char *txt)
|
|
{
|
|
unsigned char *txt1=txt;
|
|
|
|
if (!txt||!*txt)return;
|
|
for (;*txt;txt++)
|
|
switch(*txt)
|
|
{
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
case 11:
|
|
case 12:
|
|
case 13:
|
|
case 14:
|
|
case 15:
|
|
case 16:
|
|
case 17:
|
|
case 18:
|
|
case 19:
|
|
case 20:
|
|
case 21:
|
|
case 22:
|
|
case 23:
|
|
case 24:
|
|
case 25:
|
|
case 26:
|
|
case 27:
|
|
case 28:
|
|
case 29:
|
|
case 30:
|
|
case 31:
|
|
break;
|
|
|
|
case 9:
|
|
*txt1=' ';
|
|
txt1++;
|
|
break;
|
|
|
|
default:
|
|
*txt1=*txt;
|
|
txt1++;
|
|
break;
|
|
}
|
|
*txt1=0;
|
|
}
|
|
#endif
|
|
|
|
/* don't use strcasecmp because it depends on locale */
|
|
int casestrcmp(const unsigned char *s1, const unsigned char *s2)
|
|
{
|
|
while (1) {
|
|
unsigned char c1 = *s1;
|
|
unsigned char c2 = *s2;
|
|
c1 = locase(c1);
|
|
c2 = locase(c2);
|
|
if (c1 != c2) {
|
|
return (int)c1 - (int)c2;
|
|
}
|
|
if (!*s1) break;
|
|
s1++, s2++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* case insensitive compare of 2 strings */
|
|
/* comparison ends after len (or less) characters */
|
|
/* return value: 1=strings differ, 0=strings are same */
|
|
int casecmp(const unsigned char *c1, const unsigned char *c2, size_t len)
|
|
{
|
|
size_t i;
|
|
for (i = 0; i < len; i++) if (srch_cmp(c1[i], c2[i])) return 1;
|
|
return 0;
|
|
}
|
|
|
|
int casestrstr(const unsigned char *h, const unsigned char *n)
|
|
{
|
|
const unsigned char *p;
|
|
|
|
for (p=h;*p;p++)
|
|
{
|
|
if (!srch_cmp(*p,*n)) /* same */
|
|
{
|
|
const unsigned char *q, *r;
|
|
for (q=n, r=p;*r&&*q;)
|
|
{
|
|
if (!srch_cmp(*q,*r)) r++,q++; /* same */
|
|
else break;
|
|
}
|
|
if (!*q) return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
unsigned hash_string(unsigned char *u)
|
|
{
|
|
unsigned hash = 0;
|
|
for (; *u; u++)
|
|
hash = hash * 0x11 + *u;
|
|
return hash;
|
|
}
|