#ifndef utility_H__
#define utility_H__
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cstdarg>
#include <string>
namespace meow {
/*!
* @brief 類似C的printf, 不過是將格式化的字串丟到 \c std::string 裡回傳
*
* @param [in] fmt,... 同printf
* @return 一個 \c std::string
* @warning 目前格式化字串最長只支援8191個字元
*/
inline std::string stringPrintf(char const * fmt, ...){
char str[8192];
va_list args;
va_start(args, fmt);
vsnprintf(str, 8192, fmt, args);
va_end(args);
return std::string(str);
}
/*!
* @brief 將輸入字串中的某個pattern取代成另一個pattern
*
* @param [in] str 輸入的字串
* @param [in] from 要被取代的pattern
* @param [in] to 將要取代的pattern
* @return 取代後的字串
* @warning 有礙於目前實作方法很低級暴力, 時間複雜度神高
*/
inline std::string stringReplace(std::string str,
std::string const& from,
std::string const& to){
std::string out = str;
int len = from.length();
for(size_t pos; (pos = out.find(from)) != std::string::npos; ){
out.replace(pos, len, to);
}
return out;
}
/*!
* @brief 檢查給定字串的結尾是否符合給定的數個patterns中的一個
*
* @param [in] str 愈檢查的字串
* @param [in] n pattern數
* @param [in] ... 各種pattern
* @return \c true/false 表示 \b 是否有符合
* @note 參數中所有的字串都是用\c cstring 來傳遞,
* 也就是 \c char \c const* 型態
*/
inline bool cstringEndWith(char const* str, int n, ...){
int len = strlen(str);
va_list args;
va_start(args, n);
for(int i = 0; i < n; i++){
char const* arg = va_arg(args, char const*);
int arglen = strlen(arg);
if(arglen <= len && strcmp(str + len - arglen, arg) == 0){
return true;
}
}
va_end(args);
return false;
}
/*!
* @brief 若DEBUG有被define過, 將字串印到stderr, 並且附上檔名行號與所在函數名
*
* @param [in] str 要輸出的字串, 必須是c string, 即 \c char \c const* 型態
* @return 無
* @note 這是一個 \b macro
*/
#define debugPrintf(str) \
debugPrintf_(\
__FILE__,\
__FUNCTION__,\
__LINE__,\
str)
inline void debugPrintf_(char const* file,
char const* func,
size_t line,
char const* msg){
#ifdef DEBUG
fprintf(stderr, "%s[%d] %s >> %s", file, line, func, msg);
#endif // DEBUG
}
/*!
* @brief 階層式輸出
*
* 像是printf, 但多了一個 \b 巢狀 的概念, 例如:
*
* @code
* message1(level = 0)
* message2(level = 1)
* information1(level = 2)
* information2(level = 2)
* ... ok(for message2)
* message3(level = 1) ... ok
* information3(level = 1)
* message4(level = 1)
* message5(level = 2) ... ok
* message6(level = 2) ... ok
* information4(level = 2)
* ... ok(for message4)
* ... ok(for message5)
* @endcode
* @param [in] level_change 分以下三種情況:
* - == 0, 只是印出一個information
* - == 1, 印出一個message, 並且level++
* - == -1, 表示此訊息相對應最近一次level++的那個message
* @param [in] fmt, ... 跟printf一樣
* @return 無
*/
inline void messagePrintf(int level_change, char const* fmt, ...){
static int level = 0;
static int last_level = -5;
char str[8192];
va_list args;
va_start(args, fmt);
vsnprintf(str, 8192, fmt, args);
va_end(args);
if(last_level == 1 && level_change == -1){
printf(" ...%s\n", str);
}else{
if(last_level == 1) printf("\n");
int level2 = level + (level_change == -1 ? -1 : 0);
for(int i = 0; i < level2; i++) printf("| ");
printf("%s%s", (level_change == -1 ? "..." : ""), str);
if(level_change != 1) printf("\n");
}
level += level_change;
last_level = level_change;
fflush(stdout);
}
/*!
* @brief 將兩個字串用人類習慣的檔名排序方式排序
*
* 例如 a1 \< a2 \< a3 \< a10 \< a12 \< a20,
* 而不是 a1 \< a10 \< a12 \< a2 \< a20 \< a3
*
* @param [in] f1 第一個字串
* @param [in] f2 第二個字串
* @return \c true/false 表 \b f1是否該排在f2前面
*/
inline bool filenameCompare(std::string const& f1, std::string const& f2){
char const* s1 = f1.c_str();
char const* s2 = f2.c_str();
int l1 = f1.length();
int l2 = f2.length();
int i1, i2;
for(i1 = i2 = 0; i1 < l1 || i2 < l2; i1++, i2++){
if(isdigit(s1[i1]) && isdigit(s2[i2])){
int n1 = atoi(s1 + i1);
int n2 = atoi(s2 + i2);
if(n1 != n2){
return (n1 < n2);
}
while(i1 + 1 < l1 && isdigit(s1[i1 + 1])) i1++;
while(i2 + 1 < l2 && isdigit(s2[i2 + 1])) i2++;
}else{
if(s1[i1] != s2[i2]){
return s1[i1] < s2[i2];
}
}
}
return false;
}
} // meow
#endif // utility_H__