diff --git a/common/cmd.cpp b/common/cmd.cpp new file mode 100644 index 0000000..d8abf93 --- /dev/null +++ b/common/cmd.cpp @@ -0,0 +1,106 @@ +#include "cmd.h" + + + + +namespace parser +{ + static void command_line_to_arguments(const char* cmdl, std::vector& args) + { + while(*cmdl) + { + const char* h = cmdl; + while(*h == ' ' || *h == '\t') + h++; + if(*h == 0) + break; + + cmdl = h; + if(*h == '\"') + { + cmdl++; + h++; + while(*h) + { + if(*h == '\"') + break; + if(*h == '\\') + h++; + h++; + } + } + else + { + while(*h) + { + if(*h == ' ' || *h == '\t') + break; + h++; + } + } + if(h > cmdl) + args.push_back(std::string(cmdl, h - cmdl)); + else if(*h == '\"') + args.push_back(""); + + if(*h == 0) + break; + + cmdl = h + 1; + } + } +} + + + + +cmd_line::cmd_line() +{} +cmd_line::~cmd_line() +{} + +cmd_line* cmd_line::from_console(const char* tips) +{ + std::string in(""); + char ch = 0; + + if(!tips || *tips == 0) + tips = "input"; + + printf("%s%s>%s", CONSOLE_COLOR_FRONT_BLUE, tips, CONSOLE_COLOR_NONE); + while((ch = getchar()) != '\n') + in.append(1, ch); + + return cmd_line::from_command_line(in.c_str()); +} +cmd_line* cmd_line::from_command_line(const char* cmdl) +{ + cmd_line* cmd = new cmd_line(); + + cmd->cmd_line_ = cmdl; + parser::command_line_to_arguments(cmdl, cmd->arguments_); + + return cmd; +} + +size_t cmd_line::count(void) +{ + return arguments_.size(); +} +const char* cmd_line::parameter(int ind) +{ + if(ind >= 0 && ind < arguments_.size()) + return arguments_[ind].c_str(); + else + return nullptr; +} +const char* cmd_line::parameter(const char* key) +{ + for(int i = 0; i < arguments_.size() - 1; ++i) + { + if(arguments_[i] == key) + return arguments_[i + 1].c_str(); + } + + return nullptr; +} diff --git a/common/cmd.h b/common/cmd.h new file mode 100644 index 0000000..91a65c3 --- /dev/null +++ b/common/cmd.h @@ -0,0 +1,92 @@ +#pragma once + +// command line utility +// +// created on 2023-02-10 +// + +#include "referer.h" +#include +#include + +#define CONSOLE_COLOR_NONE "\033[0m" +#define CONSOLE_COLOR_FRONT_BLACK "\033[0;30m" +#define CONSOLE_COLOR_FRONT_DARK_GRAY "\033[1;30m" +#define CONSOLE_COLOR_FRONT_RED "\033[0;31m" +#define CONSOLE_COLOR_FRONT_LIGHT_RED "\033[1;31m" +#define CONSOLE_COLOR_FRONT_GREEN "\033[0;32m" +#define CONSOLE_COLOR_FRONT_LIGHT_GREEN "\033[1;32m" +#define CONSOLE_COLOR_FRONT_BROWN "\033[0;33m" +#define CONSOLE_COLOR_FRONT_YELLOW "\033[1;33m" +#define CONSOLE_COLOR_FRONT_BLUE "\033[0;34m" +#define CONSOLE_COLOR_FRONT_LIGHT_BLUE "\033[1;34m" +#define CONSOLE_COLOR_FRONT_PURPLE "\033[0;35m" +#define CONSOLE_COLOR_FRONT_LIGHT_PURPLE "\033[1;35m" +#define CONSOLE_COLOR_FRONT_CYAN "\033[0;36m" +#define CONSOLE_COLOR_FRONT_LIGHT_CYAN "\033[1;36m" +#define CONSOLE_COLOR_FRONT_LIGHT_GRAY "\033[0;37m" +#define CONSOLE_COLOR_FRONT_WHITE "\033[1;37m" + +#define CONSOLE_COLOR_BACK_BLACK "\033[0;40m" +#define CONSOLE_COLOR_BACK_DARK_GRAY "\033[1;40m" +#define CONSOLE_COLOR_BACK_RED "\033[0;41m" +#define CONSOLE_COLOR_BACK_LIGHT_RED "\033[1;41m" +#define CONSOLE_COLOR_BACK_GREEN "\033[0;42m" +#define CONSOLE_COLOR_BACK_LIGHT_GREEN "\033[1;42m" +#define CONSOLE_COLOR_BACK_BROWN "\033[0;43m" +#define CONSOLE_COLOR_BACK_YELLOW "\033[1;43m" +#define CONSOLE_COLOR_BACK_BLUE "\033[0;44m" +#define CONSOLE_COLOR_BACK_LIGHT_BLUE "\033[1;44m" +#define CONSOLE_COLOR_BACK_PURPLE "\033[0;45m" +#define CONSOLE_COLOR_BACK_LIGHT_PURPLE "\033[1;45m" +#define CONSOLE_COLOR_BACK_CYAN "\033[0;46m" +#define CONSOLE_COLOR_BACK_LIGHT_CYAN "\033[1;46m" +#define CONSOLE_COLOR_BACK_LIGHT_GRAY "\033[0;47m" +#define CONSOLE_COLOR_BACK_WHITE "\033[1;47m" + + +namespace console +{ + // special effects: + // \033[0m close all attributes + // \033[1m set high-light + // \033[4m underline + // \033[5m blink + // \033[7m reverse(反显) + // \033[8m blanking(消隐) + // \033[30m -- \033[37m set foreground color + // \033[40m -- \033[47m set background color + // + // cursor position: + // \033[nA move up n lines + // \033[nB move down n lines + // \033[nC move right n cols + // \033[nD move left n cols + // \033[y;xH set cursor position + // \033[2J clear screen + // \033[K clear the line after cursor position + // \033[s save cursor position + // \033[u restore cursor position + // \033[?25l hide cursor + // \033[?25h show cursor +}; + +class cmd_line : public refer +{ + std::string cmd_line_; + std::vector arguments_; + +protected: + cmd_line(); + ~cmd_line(); + +public: + static cmd_line* from_console(const char* tips); + static cmd_line* from_command_line(const char* cmdl); + +public: + size_t count(void); + const char* parameter(int ind); + const char* parameter(const char* key); +}; + diff --git a/common/ipc_util.cpp b/common/ipc_util.cpp index e52e9f2..4598051 100644 --- a/common/ipc_util.cpp +++ b/common/ipc_util.cpp @@ -311,6 +311,7 @@ int32_t shared_mem::open(int32_t id, size_t* bytes, const char* name) return errno; } + log_cls::log(LOG_LEVEL_DEBUG, "shared memory key: %p\n", key); size = ALIGN_INT(size, shared_mem::page_unit_); if (!bytes || *bytes != size) @@ -380,7 +381,7 @@ int32_t shared_mem::close(void) if (first_ && shm_id_ >= 0) { ret = log_cls::log_when_err(shmctl(shm_id_, IPC_RMID, nullptr), "shmctrl(IPC_RMID)"); - if (ret) + if (ret && ret != ENOENT) { // re-map buffer ... shm_buf_ = (char*)shmat(shm_id_, nullptr, 0); diff --git a/common/log_util.cpp b/common/log_util.cpp index 4650624..e2d8c2b 100644 --- a/common/log_util.cpp +++ b/common/log_util.cpp @@ -36,6 +36,8 @@ void log_cls::create_log_file(void) else fwrite("\n\n\n", 1, 3, dst_); } + else + printf("# Failed to create log file(%s): %d(%s)\n", file_.c_str(), errno, strerror(errno)); } void log_cls::log_internal(const char* txt) @@ -47,7 +49,10 @@ void log_cls::log_internal(const char* txt) LOCKER locker(lock_); if (dst_) { - fwrite(now.c_str(), 1, now.length(), dst_); + size_t wrote = fwrite(now.c_str(), 1, now.length(), dst_); + if(wrote != now.length()) + printf("# Write log failed: %d(%s)\n", errno, strerror(errno)); + fflush(dst_); if (ftell(dst_) >= max_size_) { diff --git a/common/referer.cpp b/common/referer.cpp index f30f4e2..f6cb8a3 100644 --- a/common/referer.cpp +++ b/common/referer.cpp @@ -1,5 +1,6 @@ #include "referer.h" +#include #include "log_util.h" @@ -165,9 +166,17 @@ namespace sys_util if (para[0].empty()) { - para[1] = path; + const char* now = getenv("PWD"); + bool found = strstr(path, now) == path; - return false; + if(found) + { + found = path[strlen(now)] == '/' && strstr(path + strlen(now) + 1, "/") == nullptr; + } + if(found || para[1].empty()) + para[1] = path; + + return !found; } else { @@ -210,7 +219,7 @@ namespace sys_util pid += *id - '0'; id++; } - if (*id) + if (*id || pid == 0) return true; if (cb->process) @@ -284,7 +293,11 @@ namespace sys_util 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; @@ -586,5 +599,347 @@ namespace sys_util 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; + } } diff --git a/common/referer.h b/common/referer.h index 2dd9ecc..2870823 100644 --- a/common/referer.h +++ b/common/referer.h @@ -173,4 +173,32 @@ namespace sys_util bool trim_left(std::string& str, const char* space = " \t"); bool trim_right(std::string& str, const char* space = " \t"); uint64_t from_hex_str(const char* hex, const char** end = nullptr); // convert 0x100 to 256. parameter 'end' to receive the stopped position + + // Function: convert number string to integer, support hex, dec, oct and bin + // + // Parameter: str - number string. + // 0x.../...h: as hexadecimal + // ...o: as octonary + // ...b: as binary + // ...: as decimal, or as hexadecimal if has hex letter + // + // end - to receive the ending point when covert over + // + // Return: integer, default is ZERO, you should check the ending point when this value returned + uint64_t to_int(const char* str, const char** end = nullptr); + + std::string transform_between_gbk_and_utf8(const char* in, bool to_utf8, int* err = nullptr); + std::string transform_between_utf16_and_utf8(const char* in, size_t bytes, bool to_utf8); + + std::string to_abs_path(const char* base, const char* rel_path); + std::string to_rel_path(const char* base, const char* abs_path); + + // Function: pick simple block in pair chars + // + // Parameter: head - beginning of the string, and the first character is the beginning char + // + // end - ending character of the block + // + // Return: the last positoin of the block (*ret = end), or nullptr if not matched + const char* pick_simple_block(const char* head, char end); }