mirror of http://192.168.1.51:8099/gb/code_util
944 lines
18 KiB
C++
944 lines
18 KiB
C++
|
#include "base.h"
|
||
|
|
||
|
#include <iconv.h>
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
// refer
|
||
|
refer::refer() : ref_(1)
|
||
|
{
|
||
|
on_born();
|
||
|
}
|
||
|
refer::~refer()
|
||
|
{
|
||
|
on_dead();
|
||
|
}
|
||
|
|
||
|
void refer::on_born(void)
|
||
|
{}
|
||
|
void refer::on_dead(void)
|
||
|
{}
|
||
|
|
||
|
int32_t refer::add_ref(void)
|
||
|
{
|
||
|
LOCKER lock(mutex_);
|
||
|
|
||
|
return ++ref_;
|
||
|
}
|
||
|
int32_t refer::release(void)
|
||
|
{
|
||
|
int32_t ref = 0;
|
||
|
|
||
|
{
|
||
|
LOCKER lock(mutex_);
|
||
|
ref = --ref_;
|
||
|
}
|
||
|
|
||
|
if (ref == 0)
|
||
|
delete this;
|
||
|
|
||
|
return ref;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
// chronograph
|
||
|
#include <sys/time.h>
|
||
|
|
||
|
|
||
|
chronograph::chronograph()
|
||
|
{
|
||
|
reset();
|
||
|
}
|
||
|
chronograph::~chronograph()
|
||
|
{}
|
||
|
|
||
|
bool chronograph::now(struct timeval* tv)
|
||
|
{
|
||
|
struct timezone tz = { 0 };
|
||
|
|
||
|
return gettimeofday(tv, &tz) == 0;
|
||
|
}
|
||
|
bool chronograph::now(uint64_t* seconds, uint64_t* u_seconds)
|
||
|
{
|
||
|
struct timeval tv = { 0 };
|
||
|
struct timezone tz = { 0 };
|
||
|
|
||
|
if (gettimeofday(&tv, &tz) == 0)
|
||
|
{
|
||
|
if (seconds)
|
||
|
*seconds = tv.tv_sec;
|
||
|
if (u_seconds)
|
||
|
*u_seconds = tv.tv_usec;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
std::string chronograph::now(bool with_ms/*whether with milliseconds*/) // return '2022-11-30 10:38:42.123', no '.123' if with_ms was false
|
||
|
{
|
||
|
struct timeval tv = { 0 };
|
||
|
|
||
|
if (!chronograph::now(&tv))
|
||
|
return "";
|
||
|
|
||
|
char buf[40] = { 0 };
|
||
|
time_t t = tv.tv_sec;
|
||
|
struct tm* l = localtime(&t);
|
||
|
|
||
|
if (with_ms)
|
||
|
sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d.%06d", l->tm_year + 1900, l->tm_mon + 1, l->tm_mday
|
||
|
, l->tm_hour, l->tm_min, l->tm_sec, tv.tv_usec);
|
||
|
else
|
||
|
sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d", l->tm_year + 1900, l->tm_mon + 1, l->tm_mday
|
||
|
, l->tm_hour, l->tm_min, l->tm_sec);
|
||
|
|
||
|
return buf;
|
||
|
}
|
||
|
|
||
|
uint64_t chronograph::elapse_s(void)
|
||
|
{
|
||
|
struct timeval tv = { 0 };
|
||
|
|
||
|
chronograph::now(&tv);
|
||
|
|
||
|
return tv.tv_sec - bgn_.tv_sec;
|
||
|
}
|
||
|
uint64_t chronograph::elapse_ms(void)
|
||
|
{
|
||
|
struct timeval tv = { 0 };
|
||
|
uint64_t dif = 0;
|
||
|
|
||
|
chronograph::now(&tv);
|
||
|
dif = SEC_2_MS(tv.tv_sec - bgn_.tv_sec);
|
||
|
dif += tv.tv_usec / MSEC_2_US(1);
|
||
|
dif -= bgn_.tv_usec / MSEC_2_US(1);
|
||
|
|
||
|
return dif;
|
||
|
}
|
||
|
uint64_t chronograph::elapse_us(void)
|
||
|
{
|
||
|
struct timeval tv = { 0 };
|
||
|
uint64_t dif = 0;
|
||
|
|
||
|
chronograph::now(&tv);
|
||
|
dif = SEC_2_US(tv.tv_sec - bgn_.tv_sec);
|
||
|
dif += tv.tv_usec;
|
||
|
dif -= bgn_.tv_usec;
|
||
|
|
||
|
return dif;
|
||
|
}
|
||
|
void chronograph::reset()
|
||
|
{
|
||
|
chronograph::now(&bgn_);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
// sys utility
|
||
|
#include <dirent.h>
|
||
|
#include <unistd.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
namespace sys_util
|
||
|
{
|
||
|
static bool find_module(const char* path, bool is_dir, void* param)
|
||
|
{
|
||
|
std::string* para = (std::string*)param;
|
||
|
|
||
|
if (para[0].empty())
|
||
|
{
|
||
|
const char* now = getenv("PWD");
|
||
|
bool found = strstr(path, now) == path;
|
||
|
|
||
|
if(found)
|
||
|
{
|
||
|
found = path[strlen(now)] == '/' && strstr(path + strlen(now) + 1, "/") == nullptr;
|
||
|
}
|
||
|
if(found || para[1].empty())
|
||
|
para[1] = path;
|
||
|
|
||
|
return !found;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const char* name = strrchr(path, '/');
|
||
|
if (name++ == nullptr)
|
||
|
name = path;
|
||
|
if (strstr(name, para[0].c_str()))
|
||
|
{
|
||
|
para[1] = path;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
typedef struct _enum_proc_cb
|
||
|
{
|
||
|
bool process;
|
||
|
bool(*on_found)(uint64_t pid, const char* path_name, void* param);
|
||
|
void* param;
|
||
|
}ENPROCCB, * LPENPROCCB;
|
||
|
static bool found_process(const char* path, bool is_dir, void* param)
|
||
|
{
|
||
|
LPENPROCCB cb = (LPENPROCCB)param;
|
||
|
const char* id = strrchr(path, '/');
|
||
|
uint64_t pid = 0;
|
||
|
std::string path_name("");
|
||
|
|
||
|
if (id++ == nullptr)
|
||
|
{
|
||
|
id = path;
|
||
|
}
|
||
|
while (*id)
|
||
|
{
|
||
|
if (*id < '0' || *id > '9')
|
||
|
break;
|
||
|
|
||
|
pid *= 10;
|
||
|
pid += *id - '0';
|
||
|
id++;
|
||
|
}
|
||
|
if (*id)
|
||
|
return true;
|
||
|
|
||
|
if (cb->process)
|
||
|
{
|
||
|
path_name = get_module_path(nullptr, pid);
|
||
|
id = path_name.c_str();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// get start address of pid to path_name
|
||
|
id = 0;
|
||
|
}
|
||
|
|
||
|
return cb->on_found(pid, id, cb->param);
|
||
|
}
|
||
|
static bool on_stack_line_read(char* line, void* param)
|
||
|
{
|
||
|
LPENPROCCB cb = (LPENPROCCB)param;
|
||
|
std::string m(line);
|
||
|
uint64_t off = 0;
|
||
|
size_t pos = m.find("]");
|
||
|
|
||
|
if (pos++ != std::string::npos)
|
||
|
m.erase(0, pos);
|
||
|
trim_left(m);
|
||
|
pos = m.find("+0x");
|
||
|
if (pos != std::string::npos)
|
||
|
{
|
||
|
off = from_hex_str(m.c_str() + pos + 3);
|
||
|
m.erase(pos);
|
||
|
}
|
||
|
|
||
|
return cb->on_found(off, m.c_str(), cb->param);
|
||
|
}
|
||
|
|
||
|
int32_t enum_modules(bool(*on_found)(const char* path_module_name, bool is_dir, void* param),// return false to stop enumeratin
|
||
|
void* param, // user defined data, passed into callback on_found
|
||
|
unsigned pid // process id, -1 is self
|
||
|
) // return errno
|
||
|
{
|
||
|
char path[128] = { 0 };
|
||
|
|
||
|
if (pid == -1)
|
||
|
pid = getpid();
|
||
|
sprintf(path, "/proc/%u/map_files/", pid);
|
||
|
|
||
|
return enum_files(path, on_found, param, false);
|
||
|
}
|
||
|
|
||
|
int32_t enum_files(const char* dir, // dir path
|
||
|
bool(*on_found)(const char* path_name, bool is_dir, void* param), // return false to stop enumeratin
|
||
|
void* param // user defined data, passed into callback on_found
|
||
|
, bool recursive
|
||
|
) // return errno
|
||
|
{
|
||
|
int32_t ret = 0;
|
||
|
DIR* pdir = nullptr;
|
||
|
struct dirent* ent = nullptr;
|
||
|
|
||
|
pdir = opendir(dir);
|
||
|
if (!pdir)
|
||
|
return errno;
|
||
|
|
||
|
while ((ent = readdir(pdir)))
|
||
|
{
|
||
|
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
|
||
|
continue;
|
||
|
|
||
|
std::string file(dir);
|
||
|
|
||
|
file += "/";
|
||
|
file += ent->d_name;
|
||
|
if ((ent->d_type & DT_DIR) == 0)
|
||
|
{
|
||
|
file = read_link(file.c_str());
|
||
|
if(file.empty())
|
||
|
file = std::string(dir) + "/" + ent->d_name;
|
||
|
}
|
||
|
if (!on_found(file.c_str(), ent->d_type & DT_DIR, param))
|
||
|
{
|
||
|
ret = 0x5e17;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ((ent->d_type & DT_DIR) && recursive)
|
||
|
{
|
||
|
std::string sub(dir);
|
||
|
sub += "/";
|
||
|
sub += ent->d_name;
|
||
|
ret = enum_files(sub.c_str(), on_found, param, recursive);
|
||
|
if (ret == 0x5e17)
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
closedir(pdir);
|
||
|
|
||
|
return ret == 0x5e17 ? 0 : ret;
|
||
|
}
|
||
|
|
||
|
int32_t enum_processes(bool(*on_found)(uint64_t pid, const char* path_name, void* param), void* param)
|
||
|
{
|
||
|
ENPROCCB cb;
|
||
|
|
||
|
cb.on_found = on_found;
|
||
|
cb.param = param;
|
||
|
cb.process = true;
|
||
|
|
||
|
return enum_files("/proc", found_process, &cb, false);
|
||
|
}
|
||
|
uint32_t enum_threads(uint64_t pid, bool(*on_found)(uint64_t tid, void* start_addr, void* param), void* param)
|
||
|
{
|
||
|
ENPROCCB cb;
|
||
|
|
||
|
cb.process = false;
|
||
|
cb.param = param;
|
||
|
*(void**)&cb.on_found = *(void**)&on_found;
|
||
|
|
||
|
return enum_files(("/proc/" + std::to_string(pid) + "/task").c_str(), found_process, &cb, false);
|
||
|
}
|
||
|
uint32_t get_thread_callstack(uint64_t pid, uint64_t tid, bool(*on_found)(uint64_t off, const char* module, void* param), void* param)
|
||
|
{
|
||
|
ENPROCCB cb;
|
||
|
|
||
|
cb.process = false;
|
||
|
cb.param = param;
|
||
|
*(void**)&cb.on_found = *(void**)&on_found;
|
||
|
|
||
|
return read_line(("/proc/" + std::to_string(pid) + "/task/" + std::to_string(tid) + "/stack").c_str(), on_stack_line_read, &cb);
|
||
|
}
|
||
|
uint32_t read_line(const char* file, bool(*on_line)(char* line, void* param), void* param)
|
||
|
{
|
||
|
FILE* src = fopen(file, "rb");
|
||
|
int err = 0;
|
||
|
|
||
|
if (!src)
|
||
|
return errno;
|
||
|
|
||
|
size_t ll = 1024;
|
||
|
char* line = new char[ll];
|
||
|
while (fgets(line, ll - 1, src))
|
||
|
{
|
||
|
if (!on_line(line, param))
|
||
|
break;
|
||
|
|
||
|
memset(line, 0, ll);
|
||
|
}
|
||
|
err = errno;
|
||
|
delete[] line;
|
||
|
fclose(src);
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
std::string get_module_path(const char* module_name, unsigned pid) // get module full path, nullptr is for main-exe
|
||
|
{
|
||
|
std::string param[] = { module_name ? module_name : "", "" };
|
||
|
|
||
|
enum_modules(find_module, param, pid);
|
||
|
|
||
|
return param[1];
|
||
|
}
|
||
|
std::string read_link(const char* lnk)
|
||
|
{
|
||
|
char path[512] = { 0 };
|
||
|
|
||
|
readlink(lnk, path, sizeof(path) - 1);
|
||
|
|
||
|
return path;
|
||
|
}
|
||
|
size_t get_page_size(void)
|
||
|
{
|
||
|
size_t size = sysconf(_SC_PAGESIZE);
|
||
|
|
||
|
if (size < 1024 || (size & 0x0fe0000ff)) // nKB && < 16MB
|
||
|
size = getpagesize();
|
||
|
|
||
|
return size;
|
||
|
}
|
||
|
bool create_folder(const char* dir)
|
||
|
{
|
||
|
bool ret = mkdir(dir, S_IREAD | S_IWRITE | S_IEXEC) == 0 || errno == EEXIST;
|
||
|
|
||
|
if(errno == ENOENT)
|
||
|
{
|
||
|
std::string path(dir), cur("");
|
||
|
size_t pos = path.find("/", 1);
|
||
|
|
||
|
while(pos != std::string::npos)
|
||
|
{
|
||
|
ret = mkdir(path.substr(0, pos).c_str(), S_IREAD | S_IWRITE | S_IEXEC) == 0 || errno == EEXIST;
|
||
|
if(!ret)
|
||
|
{
|
||
|
printf("mkdir(%s) = %d(%s)\n", path.substr(0, pos).c_str(), errno, strerror(errno));
|
||
|
break;
|
||
|
}
|
||
|
pos = path.find("/", pos + 1);
|
||
|
}
|
||
|
if(ret)
|
||
|
ret = mkdir(path.c_str(), S_IREAD | S_IWRITE | S_IEXEC) == 0;
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int32_t get_memory_info(uint64_t* total, uint64_t* available)
|
||
|
{
|
||
|
if (!total && !available)
|
||
|
return 0;
|
||
|
|
||
|
char line[128] = { 0 };
|
||
|
FILE* src = fopen("/proc/meminfo", "rb");
|
||
|
int32_t count = total && available ? 2 : 1;
|
||
|
unsigned long val = 0;
|
||
|
|
||
|
if (!src)
|
||
|
return errno;
|
||
|
|
||
|
while (fgets(line, sizeof(line) - 1, src))
|
||
|
{
|
||
|
if (sscanf(line, "MemTotal: %ld", &val))
|
||
|
{
|
||
|
if (total)
|
||
|
{
|
||
|
*total = val * 1024;
|
||
|
if (--count == 0)
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else if (sscanf(line, "MemFree: %ld", &val))
|
||
|
{
|
||
|
if (available)
|
||
|
{
|
||
|
*available = val * 1024;
|
||
|
if (--count == 0)
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fclose(src);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
std::string format_readable_bytes(uint64_t bytes)
|
||
|
{
|
||
|
std::string str("\0", 80);
|
||
|
|
||
|
if (bytes >= SIZE_GB(1))
|
||
|
{
|
||
|
double v = bytes * 1.0f / (SIZE_GB(1));
|
||
|
size_t pos = 0;
|
||
|
|
||
|
sprintf(&str[0], "%.2fGB", v);
|
||
|
pos = str.find(".");
|
||
|
while (pos > 3)
|
||
|
{
|
||
|
pos -= 3;
|
||
|
str.insert(pos, ",");
|
||
|
}
|
||
|
}
|
||
|
else if (bytes >= SIZE_MB(1))
|
||
|
{
|
||
|
double v = bytes * 1.0f / (SIZE_MB(1));
|
||
|
sprintf(&str[0], "%.2fMB", v);
|
||
|
}
|
||
|
else if (bytes >= SIZE_KB(1))
|
||
|
{
|
||
|
double v = bytes * 1.0f / (SIZE_KB(1));
|
||
|
sprintf(&str[0], "%.2fKB", v);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprintf(&str[0], "%uB", (unsigned)bytes);
|
||
|
}
|
||
|
|
||
|
return str;
|
||
|
}
|
||
|
std::string get_command_output(const char* cmd, uint16_t max_line_len, bool one_line)
|
||
|
{
|
||
|
FILE* src = popen(cmd, "r");
|
||
|
std::string ret("");
|
||
|
|
||
|
if (src)
|
||
|
{
|
||
|
char* buf = new char[max_line_len + 4];
|
||
|
if (buf)
|
||
|
{
|
||
|
memset(buf, 0, max_line_len + 4);
|
||
|
fgets(buf, max_line_len, src);
|
||
|
ret = buf;
|
||
|
while (!one_line && fgets(buf, max_line_len, src))
|
||
|
ret += "\n" + std::string(buf);
|
||
|
|
||
|
delete[] buf;
|
||
|
}
|
||
|
|
||
|
pclose(src);
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static bool is_char_in(const char* str, char ch)
|
||
|
{
|
||
|
if (ch == 0)
|
||
|
return false;
|
||
|
|
||
|
while (*str)
|
||
|
{
|
||
|
if (*str++ == ch)
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
bool trim_left(std::string& str, const char* space)
|
||
|
{
|
||
|
int off = 0;
|
||
|
|
||
|
for (; off < str.length(); ++off)
|
||
|
{
|
||
|
if (!is_char_in(space, str[off]))
|
||
|
break;
|
||
|
}
|
||
|
if (off)
|
||
|
str.erase(0, off);
|
||
|
|
||
|
return off > 0;
|
||
|
}
|
||
|
bool trim_right(std::string& str, const char* space)
|
||
|
{
|
||
|
int off = str.length() - 1;
|
||
|
|
||
|
for (; off >= 0; --off)
|
||
|
{
|
||
|
if (!is_char_in(space, str[off]))
|
||
|
break;
|
||
|
}
|
||
|
if (off < str.length() - 1)
|
||
|
{
|
||
|
str.erase(off + 1);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
uint64_t from_hex_str(const char* hex, const char** end)
|
||
|
{
|
||
|
uint64_t val = 0;
|
||
|
|
||
|
for (int i = 0; i < 16; ++i)
|
||
|
{
|
||
|
if (*hex >= '0' && *hex <= '9')
|
||
|
{
|
||
|
val <<= 4;
|
||
|
val += *hex - '0';
|
||
|
}
|
||
|
else if (*hex >= 'a' && *hex <= 'f')
|
||
|
{
|
||
|
val <<= 4;
|
||
|
val += *hex - 'a' + 10;
|
||
|
}
|
||
|
else if (*hex >= 'A' && *hex <= 'F')
|
||
|
{
|
||
|
val <<= 4;
|
||
|
val += *hex - 'A' + 10;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
hex++;
|
||
|
}
|
||
|
|
||
|
if (end)
|
||
|
*end = hex;
|
||
|
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
static uint64_t from_dec_str(const char* str, const char** end)
|
||
|
{
|
||
|
uint64_t val = 0;
|
||
|
|
||
|
for(int i = 0; *str && i < 19; ++i, ++str)
|
||
|
{
|
||
|
if(*str >= '0' && *str <= '9')
|
||
|
{
|
||
|
val *= 10;
|
||
|
val += *str - '0';
|
||
|
}
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
if(end)
|
||
|
*end = str;
|
||
|
|
||
|
return val;
|
||
|
}
|
||
|
static uint64_t from_oct_str(const char* str, const char** end)
|
||
|
{
|
||
|
uint64_t val = 0;
|
||
|
|
||
|
for(int i = 0; *str && i < 21; ++i, ++str)
|
||
|
{
|
||
|
if(*str >= '0' && *str <= '7')
|
||
|
{
|
||
|
val *= 8;
|
||
|
val += *str - '0';
|
||
|
}
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
if(end)
|
||
|
*end = str;
|
||
|
|
||
|
return val;
|
||
|
}
|
||
|
static uint64_t from_bin_str(const char* str, const char** end)
|
||
|
{
|
||
|
uint64_t val = 0;
|
||
|
|
||
|
for(int i = 0; *str && i < 64; ++i, ++str)
|
||
|
{
|
||
|
if(*str >= '0' && *str <= '1')
|
||
|
{
|
||
|
val *= 2;
|
||
|
val += *str - '0';
|
||
|
}
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
if(end)
|
||
|
*end = str;
|
||
|
|
||
|
return val;
|
||
|
}
|
||
|
uint64_t to_int(const char* str, const char** end)
|
||
|
{
|
||
|
if(!str || *str == 0)
|
||
|
{
|
||
|
if(end)
|
||
|
*end = str;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if(strstr(str, "0x") == str)
|
||
|
return from_hex_str(str + 2, end);
|
||
|
|
||
|
if(str[strlen(str) - 1] == 'h' || str[strlen(str) - 1] == 'H')
|
||
|
return from_hex_str(str, end);
|
||
|
if(str[strlen(str) - 1] == 'o' || str[strlen(str) - 1] == 'O')
|
||
|
return from_oct_str(str, end);
|
||
|
if(str[strlen(str) - 1] == 'b' || str[strlen(str) - 1] == 'B')
|
||
|
return from_bin_str(str, end);
|
||
|
|
||
|
bool hex = false;
|
||
|
for(int i = 0; str[i]; ++i)
|
||
|
{
|
||
|
if(str[i] < '0')
|
||
|
break;
|
||
|
if(str[i] > '9')
|
||
|
{
|
||
|
if((str[i] >= 'a' && str[i] <= 'f') ||
|
||
|
(str[i] >= 'A' && str[i] <= 'F'))
|
||
|
hex = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hex ? from_hex_str(str, end) : from_dec_str(str, end);
|
||
|
}
|
||
|
|
||
|
/* iconv_open language options:
|
||
|
|
||
|
Europe:
|
||
|
ASCII, ISO-8859-{1,2,3,4,5,7,9,10,13,14,15,16}, KOI8-R, KOI8-U, KOI8-RU,
|
||
|
CP{1250,1251,1252,1253,1254,1257}, CP{850,866},
|
||
|
Mac{Roman,CentralEurope,Iceland,Croatian,Romania},
|
||
|
Mac{Cyrillic,Ukraine,Greek,Turkish}, Macintosh
|
||
|
|
||
|
Semitic:
|
||
|
ISO-8859-{6,8}, CP{1255,1256}, CP862, Mac{Hebrew,Arabic}
|
||
|
|
||
|
Janpanese:
|
||
|
EUC-JP, SHIFT-JIS, CP932, ISO-2022-JP, ISO-2022-JP-2, ISO-2022-JP-1
|
||
|
|
||
|
Chinese:
|
||
|
EUC-CN, HZ, GBK, GB18030, EUC-TW, BIG5, CP950, BIG5-HKSCS, ISO-2022-CN, ISO-2022-CN-EXT
|
||
|
|
||
|
Korean:
|
||
|
EUC-KR, CP949, ISO-2022-KR, JOHAB
|
||
|
|
||
|
Armenian:
|
||
|
ARMSCII-8
|
||
|
|
||
|
Georgian:
|
||
|
Georgian-Academy, Georgian-PS
|
||
|
|
||
|
Thai:
|
||
|
TIS-620, CP874, MacThai
|
||
|
|
||
|
Laos:
|
||
|
MuleLao-1, CP1133
|
||
|
|
||
|
Vietnam:
|
||
|
VISCII, TCVN, CP1258
|
||
|
|
||
|
Special:
|
||
|
HP-ROMAN8, NEXTSTEP
|
||
|
|
||
|
Full Unicode:
|
||
|
UTF-8
|
||
|
UCS-2, UCS-2BE, UCS-2LE
|
||
|
UCS-4, UCS-4BE, UCS-4LE
|
||
|
UTF-16, UTF-16BE, UTF-16LE
|
||
|
UTF-32, UTF-32BE, UTF-32LE
|
||
|
UTF-7
|
||
|
JAVA
|
||
|
*/
|
||
|
std::string transform_between_gbk_and_utf8(const char* in, bool to_utf8, int *err)
|
||
|
{
|
||
|
size_t len = strlen(in) + 8, ol = len * 2;
|
||
|
char *buf = (char*)malloc(len), *oper = buf, *out = nullptr, *oper1 = nullptr;
|
||
|
iconv_t conv;
|
||
|
|
||
|
memset(buf, 0, len);
|
||
|
strcpy(buf, in);
|
||
|
if(to_utf8)
|
||
|
conv = iconv_open("UTF-8", "GBK");
|
||
|
else
|
||
|
conv = iconv_open("GBK", "UTF-8");
|
||
|
if(conv == (iconv_t)-1)
|
||
|
{
|
||
|
if(err)
|
||
|
*err = errno;
|
||
|
|
||
|
free(buf);
|
||
|
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
oper1 = out = (char*)malloc(ol);
|
||
|
memset(out, 0, ol);
|
||
|
len -= 8;
|
||
|
if(iconv(conv, &oper, &len, &oper1, &ol))
|
||
|
{
|
||
|
if(err)
|
||
|
*err = errno;
|
||
|
}
|
||
|
else if(err)
|
||
|
*err = 0;
|
||
|
|
||
|
std::string ret(out);
|
||
|
|
||
|
free(buf);
|
||
|
free(out);
|
||
|
iconv_close(conv);
|
||
|
|
||
|
return std::move(ret);
|
||
|
}
|
||
|
std::string transform_between_utf16_and_utf8(const char* in, size_t bytes, bool to_utf8)
|
||
|
{
|
||
|
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||
|
std::string ret("");
|
||
|
|
||
|
if(to_utf8)
|
||
|
{
|
||
|
unsigned short *uc = *(unsigned short**)&in, val = 0;
|
||
|
for(size_t i = 0; i < bytes / 2; ++i, ++uc)
|
||
|
{
|
||
|
val = *uc;
|
||
|
if ((*uc>=0xDC00 && *uc<=0xDFFF) || *uc==0) break; /* check for invalid. */
|
||
|
|
||
|
if (*uc>=0xD800 && *uc<=0xDBFF) /* UTF16 surrogate pairs. */
|
||
|
{
|
||
|
unsigned short uc2 = uc[1];
|
||
|
if (uc2 < 0xDC00 || uc2 > 0xDFFF) break; /* invalid second-half of surrogate. */
|
||
|
val = 0x10000 + (((*uc & 0x3FF) << 10) | (uc2 & 0x3FF));
|
||
|
}
|
||
|
|
||
|
int len = 4;
|
||
|
char buf[4] = {0}, *ptr2 = buf;
|
||
|
if (val<0x80) len=1;else if (val<0x800) len=2;else if (val<0x10000) len=3; ptr2+=len;
|
||
|
|
||
|
switch (len) {
|
||
|
case 4: *--ptr2 =((val | 0x80) & 0xBF); val >>= 6;
|
||
|
case 3: *--ptr2 =((val | 0x80) & 0xBF); val >>= 6;
|
||
|
case 2: *--ptr2 =((val | 0x80) & 0xBF); val >>= 6;
|
||
|
case 1: *--ptr2 =(val | firstByteMark[len]);
|
||
|
}
|
||
|
ret += std::string(buf, len);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
char* unic = (char*)malloc(strlen(in) * 3 + 8);
|
||
|
unsigned char * cur = (unsigned char*)unic;
|
||
|
|
||
|
while (*cur = *in++)
|
||
|
{
|
||
|
if ((*cur & 0x0f0) == 0x0e0)
|
||
|
{
|
||
|
if (((unsigned char)in[0] & 0x0c0) == 0x80 &&
|
||
|
((unsigned char)in[1] & 0x0c0) == 0x80)
|
||
|
{
|
||
|
char* hex = "0123456789ABCDEF";
|
||
|
unsigned short us = *cur & 0x0f;
|
||
|
us <<= 6;
|
||
|
us += in[0] & 0x3f;
|
||
|
us <<= 6;
|
||
|
us += in[1] & 0x3f;
|
||
|
|
||
|
*cur++ = '\\';
|
||
|
*cur++ = 'u';
|
||
|
cur[3] = hex[us & 0x0f];
|
||
|
us >>= 4;
|
||
|
cur[2] = hex[us & 0x0f];
|
||
|
us >>= 4;
|
||
|
cur[1] = hex[us & 0x0f];
|
||
|
us >>= 4;
|
||
|
cur[0] = hex[us & 0x0f];
|
||
|
cur += 3;
|
||
|
in += 2;
|
||
|
}
|
||
|
}
|
||
|
cur++;
|
||
|
}
|
||
|
*cur++ = 0;
|
||
|
ret = std::string(unic, (char*)cur - unic);
|
||
|
free(unic);
|
||
|
}
|
||
|
|
||
|
return std::move(ret);
|
||
|
}
|
||
|
|
||
|
std::string to_abs_path(const char* base, const char* rel_path)
|
||
|
{
|
||
|
if(*rel_path == '/')
|
||
|
return rel_path;
|
||
|
|
||
|
std::string b(base), r(rel_path);
|
||
|
size_t pos = 0;
|
||
|
|
||
|
while(b.length() && b[b.length() - 1] == '/')
|
||
|
b.erase(b.length() - 1);
|
||
|
|
||
|
while(r[0] == '.')
|
||
|
{
|
||
|
if(r[1] == '/')
|
||
|
r.erase(0, 2);
|
||
|
else if(r[1] == '.' && r[2] == '/')
|
||
|
{
|
||
|
pos = b.rfind('/');
|
||
|
if(pos == std::string::npos)
|
||
|
break;
|
||
|
b.erase(pos);
|
||
|
r.erase(0, 3);
|
||
|
}
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
b += "/" + r;
|
||
|
|
||
|
return std::move(b);
|
||
|
}
|
||
|
std::string to_rel_path(const char* base, const char* abs_path)
|
||
|
{
|
||
|
if(*abs_path != '/')
|
||
|
return abs_path;
|
||
|
|
||
|
std::string rel(""), b(base), a(abs_path);
|
||
|
size_t pos = 0;
|
||
|
|
||
|
while(b.length() && b[b.length() - 1] == '/')
|
||
|
b.erase(b.length() - 1);
|
||
|
|
||
|
while(a.find(b) == std::string::npos)
|
||
|
{
|
||
|
rel += "../";
|
||
|
pos = b.rfind('/');
|
||
|
if(pos == 0)
|
||
|
break;
|
||
|
b.erase(pos - 1);
|
||
|
}
|
||
|
if(rel.empty())
|
||
|
rel = "./";
|
||
|
|
||
|
return std::move(rel + a);
|
||
|
}
|
||
|
|
||
|
const char* pick_simple_block(const char* head, char end)
|
||
|
{
|
||
|
const char* tail = head + 1;
|
||
|
int cnt = 1;
|
||
|
|
||
|
while(*tail)
|
||
|
{
|
||
|
if(*tail == end)
|
||
|
{
|
||
|
cnt--;
|
||
|
if(cnt == 0)
|
||
|
break;
|
||
|
}
|
||
|
else if(*tail == *head)
|
||
|
{
|
||
|
cnt++;
|
||
|
}
|
||
|
else if(*tail == '\\')
|
||
|
{
|
||
|
tail++;
|
||
|
if(*tail == 0)
|
||
|
break;
|
||
|
}
|
||
|
tail++;
|
||
|
}
|
||
|
|
||
|
return cnt == 0 ? tail : nullptr;
|
||
|
}
|
||
|
}
|
||
|
|