aboutsummaryrefslogblamecommitdiffstats
path: root/meowpp/utility.h
blob: b430dd84567d6ddcf8406ac77c9ad710df0d7504 (plain) (tree)
1
2
3
4
5
6
7
8
9



                     


                  

                 
 
                
 













                                                                                         

 






















































































































































                                                                                                    
 
                     
#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__