mirror of
https://github.com/InfrastructureServices/vsftpd.git
synced 2025-04-19 01:24:02 +03:00
838 lines
18 KiB
C
838 lines
18 KiB
C
/*
|
|
* Part of Very Secure FTPd
|
|
* Licence: GPL v2
|
|
* Author: Chris Evans
|
|
* str.c
|
|
*
|
|
* Generic string handling functions. The fact that a string is implemented
|
|
* internally using a buffer is not exposed in the API. If you can't see
|
|
* the buffers, you can't handle them in a screwed way. Or so goes the
|
|
* theory, anyway...
|
|
*/
|
|
|
|
/* Anti-lamer measures deployed, sir! */
|
|
#define PRIVATE_HANDS_OFF_p_buf p_buf
|
|
#define PRIVATE_HANDS_OFF_len len
|
|
#define PRIVATE_HANDS_OFF_alloc_bytes alloc_bytes
|
|
#include "str.h"
|
|
|
|
/* Ick. Its for die() */
|
|
#include "utility.h"
|
|
#include "sysutil.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <wchar.h>
|
|
#include <wctype.h>
|
|
|
|
/* File local functions */
|
|
static void str_split_text_common(struct mystr* p_src, struct mystr* p_rhs,
|
|
const char* p_text, int is_reverse);
|
|
static int str_equal_internal(const char* p_buf1, unsigned int buf1_len,
|
|
const char* p_buf2, unsigned int buf2_len);
|
|
|
|
/* Private functions */
|
|
static void
|
|
s_setbuf(struct mystr* p_str, char* p_newbuf)
|
|
{
|
|
if (p_str->p_buf != 0)
|
|
{
|
|
bug("p_buf not NULL when setting it");
|
|
}
|
|
p_str->p_buf = p_newbuf;
|
|
}
|
|
|
|
void
|
|
private_str_alloc_memchunk(struct mystr* p_str, const char* p_src,
|
|
unsigned int len)
|
|
{
|
|
/* Make sure this will fit in the buffer */
|
|
unsigned int buf_needed;
|
|
if (len + 1 < len)
|
|
{
|
|
bug("integer overflow");
|
|
}
|
|
buf_needed = len + 1;
|
|
if (buf_needed > p_str->alloc_bytes)
|
|
{
|
|
str_free(p_str);
|
|
s_setbuf(p_str, vsf_sysutil_malloc(buf_needed));
|
|
p_str->alloc_bytes = buf_needed;
|
|
}
|
|
vsf_sysutil_memcpy(p_str->p_buf, p_src, len);
|
|
p_str->p_buf[len] = '\0';
|
|
p_str->len = len;
|
|
}
|
|
|
|
void
|
|
private_str_append_memchunk(struct mystr* p_str, const char* p_src,
|
|
unsigned int len)
|
|
{
|
|
unsigned int buf_needed;
|
|
if (len + p_str->len < len)
|
|
{
|
|
bug("integer overflow");
|
|
}
|
|
buf_needed = len + p_str->len;
|
|
if (buf_needed + 1 < buf_needed)
|
|
{
|
|
bug("integer overflow");
|
|
}
|
|
buf_needed++;
|
|
if (buf_needed > p_str->alloc_bytes)
|
|
{
|
|
p_str->p_buf = vsf_sysutil_realloc(p_str->p_buf, buf_needed);
|
|
p_str->alloc_bytes = buf_needed;
|
|
}
|
|
vsf_sysutil_memcpy(p_str->p_buf + p_str->len, p_src, len);
|
|
p_str->p_buf[p_str->len + len] = '\0';
|
|
p_str->len += len;
|
|
}
|
|
|
|
/* Public functions */
|
|
void
|
|
str_alloc_text(struct mystr* p_str, const char* p_src)
|
|
{
|
|
unsigned int len = vsf_sysutil_strlen(p_src);
|
|
private_str_alloc_memchunk(p_str, p_src, len);
|
|
}
|
|
|
|
void
|
|
str_copy(struct mystr* p_dest, const struct mystr* p_src)
|
|
{
|
|
private_str_alloc_memchunk(p_dest, p_src->p_buf, p_src->len);
|
|
}
|
|
|
|
const char*
|
|
str_strdup(const struct mystr* p_str)
|
|
{
|
|
return vsf_sysutil_strdup(str_getbuf(p_str));
|
|
}
|
|
|
|
const char*
|
|
str_strdup_trimmed(const struct mystr* p_str)
|
|
{
|
|
const char* p_trimmed = str_getbuf(p_str);
|
|
int h, t, newlen;
|
|
|
|
for (h = 0; h < (int)str_getlen(p_str) && vsf_sysutil_isspace(p_trimmed[h]); h++) ;
|
|
for (t = str_getlen(p_str) - 1; t >= 0 && vsf_sysutil_isspace(p_trimmed[t]); t--) ;
|
|
newlen = t - h + 1;
|
|
return (newlen > 0) ? vsf_sysutil_strndup(p_trimmed+h, (unsigned int)newlen) : 0L;
|
|
}
|
|
|
|
void
|
|
str_alloc_alt_term(struct mystr* p_str, const char* p_src, char term)
|
|
{
|
|
const char* p_search = p_src;
|
|
unsigned int len = 0;
|
|
while (*p_search != term)
|
|
{
|
|
p_search++;
|
|
len++;
|
|
if (len == 0)
|
|
{
|
|
bug("integer overflow");
|
|
}
|
|
}
|
|
private_str_alloc_memchunk(p_str, p_src, len);
|
|
}
|
|
|
|
void
|
|
str_alloc_ulong(struct mystr* p_str, unsigned long the_long)
|
|
{
|
|
str_alloc_text(p_str, vsf_sysutil_ulong_to_str(the_long));
|
|
}
|
|
|
|
void
|
|
str_alloc_filesize_t(struct mystr* p_str, filesize_t the_filesize)
|
|
{
|
|
str_alloc_text(p_str, vsf_sysutil_filesize_t_to_str(the_filesize));
|
|
}
|
|
|
|
void
|
|
str_free(struct mystr* p_str)
|
|
{
|
|
if (p_str->p_buf != 0)
|
|
{
|
|
vsf_sysutil_free(p_str->p_buf);
|
|
}
|
|
p_str->p_buf = 0;
|
|
p_str->len = 0;
|
|
p_str->alloc_bytes = 0;
|
|
}
|
|
|
|
void
|
|
str_empty(struct mystr* p_str)
|
|
{
|
|
/* Ensure a buffer is allocated. */
|
|
(void) str_getbuf(p_str);
|
|
str_trunc(p_str, 0);
|
|
}
|
|
|
|
void
|
|
str_trunc(struct mystr* p_str, unsigned int trunc_len)
|
|
{
|
|
if (trunc_len >= p_str->alloc_bytes)
|
|
{
|
|
bug("trunc_len not smaller than alloc_bytes in str_trunc");
|
|
}
|
|
p_str->len = trunc_len;
|
|
p_str->p_buf[p_str->len] = '\0';
|
|
}
|
|
|
|
void
|
|
str_reserve(struct mystr* p_str, unsigned int res_len)
|
|
{
|
|
/* Reserve space for the trailing zero as well. */
|
|
res_len++;
|
|
if (res_len == 0)
|
|
{
|
|
bug("integer overflow");
|
|
}
|
|
if (res_len > p_str->alloc_bytes)
|
|
{
|
|
p_str->p_buf = vsf_sysutil_realloc(p_str->p_buf, res_len);
|
|
p_str->alloc_bytes = res_len;
|
|
}
|
|
p_str->p_buf[res_len - 1] = '\0';
|
|
}
|
|
|
|
int
|
|
str_isempty(const struct mystr* p_str)
|
|
{
|
|
return (p_str->len == 0);
|
|
}
|
|
|
|
unsigned int
|
|
str_getlen(const struct mystr* p_str)
|
|
{
|
|
return p_str->len;
|
|
}
|
|
|
|
const char*
|
|
str_getbuf(const struct mystr* p_str)
|
|
{
|
|
if (p_str->p_buf == 0)
|
|
{
|
|
if (p_str->len != 0 || p_str->alloc_bytes != 0)
|
|
{
|
|
bug("p_buf NULL and len or alloc_bytes != 0 in str_getbuf");
|
|
}
|
|
private_str_alloc_memchunk((struct mystr*)p_str, 0, 0);
|
|
}
|
|
return p_str->p_buf;
|
|
}
|
|
|
|
int
|
|
str_strcmp(const struct mystr* p_str1, const struct mystr* p_str2)
|
|
{
|
|
return str_equal_internal(p_str1->p_buf, p_str1->len,
|
|
p_str2->p_buf, p_str2->len);
|
|
}
|
|
|
|
static int
|
|
str_equal_internal(const char* p_buf1, unsigned int buf1_len,
|
|
const char* p_buf2, unsigned int buf2_len)
|
|
{
|
|
int retval;
|
|
unsigned int minlen = buf1_len;
|
|
if (buf2_len < minlen)
|
|
{
|
|
minlen = buf2_len;
|
|
}
|
|
retval = vsf_sysutil_memcmp(p_buf1, p_buf2, minlen);
|
|
if (retval != 0 || buf1_len == buf2_len)
|
|
{
|
|
return retval;
|
|
}
|
|
/* Strings equal but lengths differ. The greater one, then, is the longer */
|
|
return (int) (buf1_len - buf2_len);
|
|
}
|
|
|
|
int
|
|
str_equal(const struct mystr* p_str1, const struct mystr* p_str2)
|
|
{
|
|
return (str_strcmp(p_str1, p_str2) == 0);
|
|
}
|
|
|
|
int
|
|
str_equal_text(const struct mystr* p_str, const char* p_text)
|
|
{
|
|
unsigned int cmplen = vsf_sysutil_strlen(p_text);
|
|
return (str_equal_internal(p_str->p_buf, p_str->len, p_text, cmplen) == 0);
|
|
}
|
|
|
|
void
|
|
str_append_str(struct mystr* p_str, const struct mystr* p_other)
|
|
{
|
|
private_str_append_memchunk(p_str, p_other->p_buf, p_other->len);
|
|
}
|
|
|
|
void
|
|
str_append_text(struct mystr* p_str, const char* p_src)
|
|
{
|
|
unsigned int len = vsf_sysutil_strlen(p_src);
|
|
private_str_append_memchunk(p_str, p_src, len);
|
|
}
|
|
|
|
void
|
|
str_append_char(struct mystr* p_str, char the_char)
|
|
{
|
|
private_str_append_memchunk(p_str, &the_char, sizeof(the_char));
|
|
}
|
|
|
|
void
|
|
str_append_ulong(struct mystr* p_str, unsigned long the_ulong)
|
|
{
|
|
str_append_text(p_str, vsf_sysutil_ulong_to_str(the_ulong));
|
|
}
|
|
|
|
void
|
|
str_append_filesize_t(struct mystr* p_str, filesize_t the_filesize)
|
|
{
|
|
str_append_text(p_str, vsf_sysutil_filesize_t_to_str(the_filesize));
|
|
}
|
|
|
|
void
|
|
str_append_double(struct mystr* p_str, double the_double)
|
|
{
|
|
str_append_text(p_str, vsf_sysutil_double_to_str(the_double));
|
|
}
|
|
|
|
void
|
|
str_upper(struct mystr* p_str)
|
|
{
|
|
unsigned int i;
|
|
for (i=0; i < p_str->len; i++)
|
|
{
|
|
p_str->p_buf[i] = (char) vsf_sysutil_toupper(p_str->p_buf[i]);
|
|
}
|
|
}
|
|
|
|
void
|
|
str_rpad(struct mystr* p_str, const unsigned int min_width)
|
|
{
|
|
unsigned int to_pad;
|
|
if (p_str->len >= min_width)
|
|
{
|
|
return;
|
|
}
|
|
to_pad = min_width - p_str->len;
|
|
while (to_pad--)
|
|
{
|
|
str_append_char(p_str, ' ');
|
|
}
|
|
}
|
|
|
|
void
|
|
str_lpad(struct mystr* p_str, const unsigned int min_width)
|
|
{
|
|
static struct mystr s_tmp_str;
|
|
unsigned int to_pad;
|
|
if (p_str->len >= min_width)
|
|
{
|
|
return;
|
|
}
|
|
to_pad = min_width - p_str->len;
|
|
str_empty(&s_tmp_str);
|
|
while (to_pad--)
|
|
{
|
|
str_append_char(&s_tmp_str, ' ');
|
|
}
|
|
str_append_str(&s_tmp_str, p_str);
|
|
str_copy(p_str, &s_tmp_str);
|
|
}
|
|
|
|
void
|
|
str_replace_char(struct mystr* p_str, char from, char to)
|
|
{
|
|
unsigned int i;
|
|
for (i=0; i < p_str->len; i++)
|
|
{
|
|
if (p_str->p_buf[i] == from)
|
|
{
|
|
p_str->p_buf[i] = to;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
str_replace_text(struct mystr* p_str, const char* p_from, const char* p_to)
|
|
{
|
|
static struct mystr s_lhs_chunk_str;
|
|
static struct mystr s_rhs_chunk_str;
|
|
unsigned int lhs_len;
|
|
str_copy(&s_lhs_chunk_str, p_str);
|
|
str_free(p_str);
|
|
do
|
|
{
|
|
lhs_len = str_getlen(&s_lhs_chunk_str);
|
|
str_split_text(&s_lhs_chunk_str, &s_rhs_chunk_str, p_from);
|
|
/* Copy lhs to destination */
|
|
str_append_str(p_str, &s_lhs_chunk_str);
|
|
/* If this was a 'hit', append the 'to' text */
|
|
if (str_getlen(&s_lhs_chunk_str) < lhs_len)
|
|
{
|
|
str_append_text(p_str, p_to);
|
|
}
|
|
/* Current rhs becomes new lhs */
|
|
str_copy(&s_lhs_chunk_str, &s_rhs_chunk_str);
|
|
} while (!str_isempty(&s_lhs_chunk_str));
|
|
}
|
|
|
|
void
|
|
str_split_char(struct mystr* p_src, struct mystr* p_rhs, char c)
|
|
{
|
|
/* Just use str_split_text */
|
|
char ministr[2];
|
|
ministr[0] = c;
|
|
ministr[1] = '\0';
|
|
str_split_text(p_src, p_rhs, ministr);
|
|
}
|
|
|
|
void
|
|
str_split_char_reverse(struct mystr* p_src, struct mystr* p_rhs, char c)
|
|
{
|
|
/* Just use str_split_text_reverse */
|
|
char ministr[2];
|
|
ministr[0] = c;
|
|
ministr[1] = '\0';
|
|
str_split_text_reverse(p_src, p_rhs, ministr);
|
|
}
|
|
|
|
void
|
|
str_split_text(struct mystr* p_src, struct mystr* p_rhs, const char* p_text)
|
|
{
|
|
str_split_text_common(p_src, p_rhs, p_text, 0);
|
|
}
|
|
|
|
void
|
|
str_split_text_reverse(struct mystr* p_src, struct mystr* p_rhs,
|
|
const char* p_text)
|
|
{
|
|
str_split_text_common(p_src, p_rhs, p_text, 1);
|
|
}
|
|
|
|
static void
|
|
str_split_text_common(struct mystr* p_src, struct mystr* p_rhs,
|
|
const char* p_text, int is_reverse)
|
|
{
|
|
struct str_locate_result locate_result;
|
|
unsigned int indexx;
|
|
unsigned int search_len = vsf_sysutil_strlen(p_text);
|
|
if (is_reverse)
|
|
{
|
|
locate_result = str_locate_text_reverse(p_src, p_text);
|
|
}
|
|
else
|
|
{
|
|
locate_result = str_locate_text(p_src, p_text);
|
|
}
|
|
/* Not found? */
|
|
if (!locate_result.found)
|
|
{
|
|
str_empty(p_rhs);
|
|
return;
|
|
}
|
|
indexx = locate_result.index;
|
|
if (indexx + search_len > p_src->len)
|
|
{
|
|
bug("indexx invalid in str_split_text");
|
|
}
|
|
/* Build rhs */
|
|
private_str_alloc_memchunk(p_rhs, p_src->p_buf + indexx + search_len,
|
|
p_src->len - indexx - search_len);
|
|
/* Build lhs */
|
|
str_trunc(p_src, indexx);
|
|
}
|
|
|
|
struct str_locate_result
|
|
str_locate_str(const struct mystr* p_str, const struct mystr* p_look_str)
|
|
{
|
|
return str_locate_text(p_str, str_getbuf(p_look_str));
|
|
}
|
|
|
|
struct str_locate_result
|
|
str_locate_str_reverse(const struct mystr* p_str,
|
|
const struct mystr* p_look_str)
|
|
{
|
|
return str_locate_text_reverse(p_str, str_getbuf(p_look_str));
|
|
}
|
|
|
|
struct str_locate_result
|
|
str_locate_char(const struct mystr* p_str, char look_char)
|
|
{
|
|
char look_str[2];
|
|
look_str[0] = look_char;
|
|
look_str[1] = '\0';
|
|
return str_locate_text(p_str, look_str);
|
|
}
|
|
|
|
struct str_locate_result
|
|
str_locate_chars(const struct mystr* p_str, const char* p_chars)
|
|
{
|
|
struct str_locate_result retval;
|
|
unsigned int num_chars = vsf_sysutil_strlen(p_chars);
|
|
unsigned int i = 0;
|
|
retval.found = 0;
|
|
retval.char_found = 0;
|
|
retval.index = 0;
|
|
for (; i < p_str->len; ++i)
|
|
{
|
|
unsigned int j = 0;
|
|
char this_char = p_str->p_buf[i];
|
|
for (; j < num_chars; ++j)
|
|
{
|
|
if (p_chars[j] == this_char)
|
|
{
|
|
retval.found = 1;
|
|
retval.index = i;
|
|
retval.char_found = p_chars[j];
|
|
return retval;
|
|
}
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
struct str_locate_result
|
|
str_locate_text(const struct mystr* p_str, const char* p_text)
|
|
{
|
|
struct str_locate_result retval;
|
|
unsigned int i;
|
|
unsigned int text_len = vsf_sysutil_strlen(p_text);
|
|
retval.found = 0;
|
|
retval.char_found = 0;
|
|
retval.index = 0;
|
|
if (text_len == 0 || text_len > p_str->len)
|
|
{
|
|
/* Not found */
|
|
return retval;
|
|
}
|
|
for (i=0; i <= (p_str->len - text_len); i++)
|
|
{
|
|
if (vsf_sysutil_memcmp(p_str->p_buf + i, p_text, text_len) == 0)
|
|
{
|
|
retval.found = 1;
|
|
retval.index = i;
|
|
return retval;
|
|
}
|
|
}
|
|
/* Not found */
|
|
return retval;
|
|
}
|
|
|
|
struct str_locate_result
|
|
str_locate_text_reverse(const struct mystr* p_str, const char* p_text)
|
|
{
|
|
struct str_locate_result retval;
|
|
unsigned int i;
|
|
unsigned int text_len = vsf_sysutil_strlen(p_text);
|
|
retval.found = 0;
|
|
retval.char_found = 0;
|
|
retval.index = 0;
|
|
if (text_len == 0 || text_len > p_str->len)
|
|
{
|
|
return retval;
|
|
}
|
|
i = p_str->len - text_len;
|
|
/* Want to go through loop once even if i==0 */
|
|
while (1)
|
|
{
|
|
if (vsf_sysutil_memcmp(p_str->p_buf + i, p_text, text_len) == 0)
|
|
{
|
|
retval.found = 1;
|
|
retval.index = i;
|
|
return retval;
|
|
}
|
|
if (i == 0)
|
|
{
|
|
break;
|
|
}
|
|
i--;
|
|
}
|
|
/* Not found */
|
|
return retval;
|
|
}
|
|
|
|
void
|
|
str_left(const struct mystr* p_str, struct mystr* p_out, unsigned int chars)
|
|
{
|
|
if (chars > p_str->len)
|
|
{
|
|
bug("chars invalid in str_left");
|
|
}
|
|
private_str_alloc_memchunk(p_out, p_str->p_buf, chars);
|
|
}
|
|
|
|
void
|
|
str_right(const struct mystr* p_str, struct mystr* p_out, unsigned int chars)
|
|
{
|
|
unsigned int indexx = p_str->len - chars;
|
|
if (chars > p_str->len)
|
|
{
|
|
bug("chars invalid in str_right");
|
|
}
|
|
private_str_alloc_memchunk(p_out, p_str->p_buf + indexx, chars);
|
|
}
|
|
|
|
void
|
|
str_mid_to_end(const struct mystr* p_str, struct mystr* p_out,
|
|
unsigned int indexx)
|
|
{
|
|
if (indexx > p_str->len)
|
|
{
|
|
bug("invalid indexx in str_mid_to_end");
|
|
}
|
|
private_str_alloc_memchunk(p_out, p_str->p_buf + indexx,
|
|
p_str->len - indexx);
|
|
}
|
|
|
|
char
|
|
str_get_char_at(const struct mystr* p_str, const unsigned int indexx)
|
|
{
|
|
if (indexx >= p_str->len)
|
|
{
|
|
bug("bad indexx in str_get_char_at");
|
|
}
|
|
return p_str->p_buf[indexx];
|
|
}
|
|
|
|
int
|
|
str_contains_space(const struct mystr* p_str)
|
|
{
|
|
unsigned int i;
|
|
for (i=0; i < p_str->len; i++)
|
|
{
|
|
if (vsf_sysutil_isspace(p_str->p_buf[i]))
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
str_all_space(const struct mystr* p_str)
|
|
{
|
|
unsigned int i;
|
|
for (i=0; i < p_str->len; i++)
|
|
{
|
|
if (!vsf_sysutil_isspace(p_str->p_buf[i]))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
str_contains_unprintable(const struct mystr* p_str)
|
|
{
|
|
unsigned int i;
|
|
for (i=0; i < p_str->len; i++)
|
|
{
|
|
if (!vsf_sysutil_isprint(p_str->p_buf[i]))
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
str_atoi(const struct mystr* p_str)
|
|
{
|
|
return vsf_sysutil_atoi(str_getbuf(p_str));
|
|
}
|
|
|
|
filesize_t
|
|
str_a_to_filesize_t(const struct mystr* p_str)
|
|
{
|
|
return vsf_sysutil_a_to_filesize_t(str_getbuf(p_str));
|
|
}
|
|
|
|
unsigned int
|
|
str_octal_to_uint(const struct mystr* p_str)
|
|
{
|
|
return vsf_sysutil_octal_to_uint(str_getbuf(p_str));
|
|
}
|
|
|
|
int
|
|
str_getline(const struct mystr* p_str, struct mystr* p_line_str,
|
|
unsigned int* p_pos)
|
|
{
|
|
unsigned int start_pos = *p_pos;
|
|
unsigned int curr_pos = start_pos;
|
|
unsigned int buf_len = str_getlen(p_str);
|
|
const char* p_buf = str_getbuf(p_str);
|
|
unsigned int out_len;
|
|
if (start_pos > buf_len)
|
|
{
|
|
bug("p_pos out of range in str_getline");
|
|
}
|
|
str_empty(p_line_str);
|
|
if (start_pos == buf_len)
|
|
{
|
|
return 0;
|
|
}
|
|
while (curr_pos < buf_len && p_buf[curr_pos] != '\n')
|
|
{
|
|
curr_pos++;
|
|
if (curr_pos == 0)
|
|
{
|
|
bug("integer overflow");
|
|
}
|
|
}
|
|
out_len = curr_pos - start_pos;
|
|
/* If we ended on a \n - skip it */
|
|
if (curr_pos < buf_len && p_buf[curr_pos] == '\n')
|
|
{
|
|
curr_pos++;
|
|
if (curr_pos == 0)
|
|
{
|
|
bug("integer overflow");
|
|
}
|
|
}
|
|
private_str_alloc_memchunk(p_line_str, p_buf + start_pos, out_len);
|
|
*p_pos = curr_pos;
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
str_contains_line(const struct mystr* p_str, const struct mystr* p_line_str)
|
|
{
|
|
static struct mystr s_curr_line_str;
|
|
unsigned int pos = 0;
|
|
while (str_getline(p_str, &s_curr_line_str, &pos))
|
|
{
|
|
if (str_equal(&s_curr_line_str, p_line_str))
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
str_replace_unprintable(struct mystr* p_str, char new_char)
|
|
{
|
|
unsigned int i;
|
|
for (i=0; i < p_str->len; i++)
|
|
{
|
|
if (!vsf_sysutil_isprint(p_str->p_buf[i]))
|
|
{
|
|
p_str->p_buf[i] = new_char;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
str_replace_unprintable_with_hex(struct mystr* p_str)
|
|
{
|
|
unsigned int ups_size = sizeof(unsigned int) * (p_str->len);
|
|
if (ups_size < p_str->len)
|
|
{
|
|
str_replace_unprintable(p_str, '?');
|
|
str_append_text(p_str, ": BUG: string is too long");
|
|
bug(p_str->p_buf);
|
|
}
|
|
unsigned int* ups = vsf_sysutil_malloc(ups_size);
|
|
unsigned int up_count = 0;
|
|
for (unsigned int i=0; i < p_str->len; i++)
|
|
{
|
|
if (!vsf_sysutil_isprint(p_str->p_buf[i]))
|
|
{
|
|
ups[up_count++] = i;
|
|
}
|
|
}
|
|
str_replace_positions_with_hex(p_str, ups, up_count);
|
|
vsf_sysutil_free(ups);
|
|
}
|
|
|
|
void str_replace_unprintable_with_hex_wc(struct mystr* p_str)
|
|
{
|
|
unsigned int ups_size = sizeof(unsigned int) * (p_str->len);
|
|
if (ups_size < p_str->len)
|
|
{
|
|
str_replace_unprintable(p_str, '?');
|
|
str_append_text(p_str, ": BUG: string is too long");
|
|
bug(p_str->p_buf);
|
|
}
|
|
unsigned int* ups = vsf_sysutil_malloc(ups_size);
|
|
unsigned int up_count = 0;
|
|
|
|
size_t current = 0;
|
|
wchar_t pwc;
|
|
mbstate_t ps;
|
|
memset(&ps, 0, sizeof(ps));
|
|
ssize_t len = 0;
|
|
while ((len = mbrtowc(&pwc, p_str->p_buf, p_str->len - current, &ps)) > 0)
|
|
{
|
|
if (!iswprint(pwc))
|
|
{
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
ups[up_count++] = current++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
current += len;
|
|
}
|
|
}
|
|
if (len < 0)
|
|
{
|
|
while (current < p_str->len)
|
|
{
|
|
ups[up_count++] = current++;
|
|
}
|
|
}
|
|
str_replace_positions_with_hex(p_str, ups, up_count);
|
|
vsf_sysutil_free(ups);
|
|
}
|
|
|
|
void
|
|
str_replace_positions_with_hex(struct mystr* p_str, const unsigned int* poss, const unsigned int pos_count)
|
|
{
|
|
if (pos_count == 0)
|
|
return;
|
|
|
|
struct mystr tmp_str = INIT_MYSTR;
|
|
str_reserve(&tmp_str, p_str->len + 3 * pos_count);
|
|
unsigned int current = 0;
|
|
|
|
for (unsigned int i=0; i < pos_count; i++)
|
|
{
|
|
unsigned int pos = poss[i];
|
|
|
|
if (current < pos)
|
|
private_str_append_memchunk(&tmp_str, p_str->p_buf + current, pos - current);
|
|
|
|
char hex_buf[5];
|
|
memset(hex_buf, 0, sizeof(hex_buf));
|
|
sprintf(hex_buf, "\\x%02X", (unsigned char) p_str->p_buf[pos]);
|
|
str_append_text(&tmp_str, hex_buf);
|
|
current = pos + 1;
|
|
}
|
|
|
|
if (current < p_str->len)
|
|
private_str_append_memchunk(&tmp_str, p_str->p_buf + current, p_str->len - current);
|
|
|
|
str_copy(p_str, &tmp_str);
|
|
str_free(&tmp_str);
|
|
}
|
|
|
|
void
|
|
str_basename (struct mystr* d_str, const struct mystr* path)
|
|
{
|
|
static struct mystr tmp;
|
|
|
|
str_copy (&tmp, path);
|
|
str_split_char_reverse(&tmp, d_str, '/');
|
|
|
|
if (str_isempty(d_str))
|
|
str_copy (d_str, path);
|
|
}
|