/****************************************************************************** TAB変換ツール -tabform- tabform ソースファイル Copyright(C) 2007 Wraith. All rights reserved. Coded by Wraith in May 27, 2007. ******************************************************************************/ /////////////////////////////////////////////////////////////////////////////// // // ■ tabform.cpp // http://tricklib.com/cxx/ex/tabform/tabform.cpp // // □ リファレンス・サポートページ // http://tricklib.com/cxx/ex/tabform/ // // □ ライセンス情報 // http://tricklib.com/license.htm // // □ コンパイル方法 // case Borland C++ // bcc32 tabform.cpp // case Visual C++ // cl /GX tabform.cpp // case CodeWarrior // mwcc tabform.cpp // case gcc // g++ tabform.cpp // // ////////////////////////////////////////////////////////////////////////////// // // Includes // #include #include #include #include #include #include #include #include #include ////////////////////////////////////////////////////////////////////////////// // // Declare auto closers // #if defined(WIN32) && !defined(__GNUC__) template class demi { public: T value; demi() {} demi(const T &X) :value(X) {} operator T& () { return value; } operator const T& () const { return value; } T * operator & () { return &value; } const T * operator & () const { return &value; } T & operator () () { return value; } const T & operator () () const { return value; } }; #define DECLARE_AUTO_CLOSE(name, type, param, init, close_command) \ class name :public demi \ { \ public: \ name(param) :demi(init) { } \ ~name() \ { \ close(); \ } \ void close() \ { \ if (value) \ { \ close_command; \ value = NULL; \ } \ } \ }; DECLARE_AUTO_CLOSE(AUTO_FINDHANDLE, HANDLE, HANDLE X = INVALID_HANDLE_VALUE, X, INVALID_HANDLE_VALUE != value && (FindClose(value), false)) #endif ////////////////////////////////////////////////////////////////////////////// // // Win32 Error // #if defined(WIN32) && !defined(__GNUC__) class win32_error :public std::runtime_error { DWORD code; public: win32_error(DWORD X_code = GetLastError()) :std::runtime_error(win32_error::make_error_message(X_code)), code(X_code) { } static const std::string make_error_message(DWORD X_code = GetLastError()); DWORD get_error_code() const { return code; } const char * get_error_message() const { return what(); } }; const std::string win32_error::make_error_message(DWORD X_code) { LPVOID lpMsgBuf; FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, X_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&lpMsgBuf, 0, NULL); const std::string result = (const char *)lpMsgBuf; LocalFree(lpMsgBuf); return result; } inline HANDLE check_HANDLE(HANDLE stream) { if (INVALID_HANDLE_VALUE == stream) { throw win32_error(); } return stream; } #endif ////////////////////////////////////////////////////////////////////////////// // // Command-line Interface // #if defined(WIN32) && !defined(__GNUC__) #define EXIT_CODE_SUCCESS S_OK; #define EXIT_CODE_FAILURE E_FAIL; #else #define EXIT_CODE_SUCCESS EXIT_SUCCESS; #define EXIT_CODE_FAILURE EXIT_FAILURE; #endif // // ... // typedef const std::string (*form_proc_type)(const std::string &original, int space_number, bool is_indent_only); const std::string tab_to_spacies(const std::string &original, int space_number, bool is_indent_only); const std::string spacies_to_tab(const std::string &original, int space_number, bool is_indent_only); class argument_bank { public: form_proc_type form_proc; int space_number; bool is_indent_only; std::vector target_files; argument_bank(int argc, char *args[]) :form_proc(NULL) { if (argc < 3) { return; } if (NULL == strchr("/-", args[1][0])) { return; } switch(args[1][1]) { case 'S': case 's': form_proc = tab_to_spacies; break; case 'T': case 't': form_proc = spacies_to_tab; break; default: return; } switch(args[1][strlen(args[1])-1]) { case 'I': case 'i': is_indent_only = true; break; default: is_indent_only = false; break; } space_number = atoi(args[1] +2); for(int i = 2; i < argc; ++i) { target_files.push_back(args[i]); } } }; const std::string tab_to_spacies(const std::string &original, int space_number, bool is_indent_only) { assert(2 <= space_number); assert(space_number <= 80); std::string result; const int buffer_size = 1024; char buffer[buffer_size]; int buffer_i = 0; for(std::string::const_iterator o_i = original.begin(); o_i != original.end(); ++o_i) { if ('\t' == *o_i) { // ソフトタブへの変換 do { buffer[buffer_i++] = ' '; } while(buffer_i %space_number); } else if (' ' == *o_i || !is_indent_only) { // buffer[buffer_i++] = *o_i; } else { // 対象がインデントだけの場合はここでお終い do { buffer[buffer_i++] = *o_i; if (buffer_size <= buffer_i) { result.append(buffer, buffer_i); buffer_i = 0; } ++o_i; } while(o_i != original.end()); break; } if ((buffer_size -space_number) <= buffer_i) { result.append(buffer, buffer_i); buffer_i = 0; } } if (0 < buffer_i) { result.append(buffer, buffer_i); } return result; } const std::string spacies_to_tab(const std::string &original, int space_number, bool is_indent_only) { assert(1 <= space_number); assert(space_number <= 80); std::string result; const int buffer_size = 1024; char buffer[buffer_size]; int buffer_i = 0; int char_i = 0; for(std::string::const_iterator o_i = original.begin(); o_i != original.end(); ++o_i) { if (' ' == *o_i) { int backset_i = buffer_i; buffer[buffer_i++] = ' '; ++char_i; // ハードタブへの変換 if (0 == (char_i %space_number)) { int count = 0; do { --backset_i; ++count; } while(0 <= backset_i && ' ' == buffer[backset_i]); if (2 <= count) { // スペースが2個以上連続しているならハードタブに変換 buffer_i = ++backset_i; do { buffer[buffer_i++] = '\t'; } while(0 < (count -= space_number)); } } } else if ('\t' == *o_i) { char_i = ((char_i /space_number) +1) *space_number; buffer[buffer_i++] = *o_i; } else { if (is_indent_only) { // 対象がインデントだけの場合はここでお終い do { buffer[buffer_i++] = *o_i; if ((buffer_size -space_number) <= buffer_i) { result.append(buffer, buffer_i); buffer_i = 0; } ++o_i; } while(o_i != original.end()); break; } buffer[buffer_i++] = *o_i; ++char_i; } if ((buffer_size -space_number) <= buffer_i) { int append_size = (buffer_i /space_number) *space_number; result.append(buffer, append_size); if (append_size < buffer_i) { memmove(buffer, buffer +append_size, buffer_i -append_size); } buffer_i = append_size; } } if (0 < buffer_i) { result.append(buffer, buffer_i); } return result; } void tabform(const argument_bank &arg_bank, const std::string &filename) { std::cout << "update: " << filename << std::endl; const std::string bak_filename = filename +".bak"; remove(bak_filename.c_str()); rename(filename.c_str(), bak_filename.c_str()); std::ifstream ifile(bak_filename.c_str()); std::ofstream ofile(filename.c_str()); if (!ifile || !ofile) { std::cerr << "File open failed." << std::endl; throw EXIT_CODE_FAILURE; } bool is_first = true; while(!(ifile.eof())) { if (!is_first) { ofile << std::endl; } else { is_first = false; } const int buffer_size = 1024; char buffer[buffer_size]; ifile.getline(buffer, buffer_size); std::string current_line(buffer, ifile.gcount()); std::string proced_line = arg_bank.form_proc(current_line, arg_bank.space_number, arg_bank.is_indent_only); ofile << proced_line.c_str(); } } #if defined(WIN32) && !defined(__GNUC__) // // ワイルドカードの処理 // void tabform_with_wildcard(const argument_bank &arg_bank, const std::string &filename) { WIN32_FIND_DATA X_WFD = { 0 }; std::string base_path; std::string::size_type p = filename.rfind("\\"); if (std::string::npos != p) { base_path = filename.substr(0, p +1); } AUTO_FINDHANDLE find_handle = check_HANDLE(FindFirstFile(filename.c_str(), &X_WFD)); do { if (FILE_ATTRIBUTE_DIRECTORY != (FILE_ATTRIBUTE_DIRECTORY &X_WFD.dwFileAttributes)) { tabform(arg_bank, base_path +X_WFD.cFileName); } } while(FindNextFile(find_handle, &X_WFD)); } #endif int main(int argc, char *args[]) { try { argument_bank arg_bank(argc, args); if (NULL != arg_bank.form_proc) { if (arg_bank.space_number < 2 || 80 < arg_bank.space_number) { std::cout << "SPACEの数は 2 〜 80 の間で指定してください。" << std::endl; } else { for(std::vector::const_iterator i = arg_bank.target_files.begin(); i != arg_bank.target_files.end(); ++i) { #if defined(WIN32) && !defined(__GNUC__) tabform_with_wildcard #else tabform #endif (arg_bank, *i); } } } else { if (2 <= argc) { std::cout << args[1] << " is unkwnon sub-command." << std::endl; } std::cout << std::endl; std::cout << "使い方: tabform オプション 対象ファイル" << std::endl; std::cout << std::endl; std::cout << "※SJISであることが前提です。" << std::endl; std::cout << std::endl; std::cout << "オプション" << std::endl; std::cout << " -tn[i] nをベースにスペースをタブに変換します。" << std::endl; std::cout << " -sn[i] nをベースにタブをスペースに変換します。" << std::endl; std::cout << std::endl; std::cout << " i を指定するとインデントのみを変換の対象にします。" << std::endl; std::cout << std::endl; std::cout << "指定例" << std::endl; std::cout << " -t4 ... 4をベースにスペースをタブに変換します。" << std::endl; std::cout << " -t4i ... 4をベースにインデント中のスペースのみをタブに変換します。" << std::endl; std::cout << " -s8 ... 8をベースにタブをスペースに変換します。" << std::endl; std::cout << std::endl; std::cout << "cf. http://tricklib.com/cxx/ex/tabform/" << std::endl; } } #if defined(WIN32) && !defined(__GNUC__) catch(const win32_error &e) { std::cerr << e.what() << std::endl; return e.get_error_code(); } #endif catch(const std::exception &e) { std::cerr << e.what() << std::endl; return EXIT_CODE_FAILURE; } catch(...) { std::cerr << "Unexpected error." << std::endl; return EXIT_CODE_FAILURE; } return EXIT_CODE_SUCCESS; } /****************************************************************************** □■□■ Wraith the Trickster □■□■ ■□■□ 〜I'll go with heaven's advantage and fool's wisdom.〜 ■□■□ ******************************************************************************/