├── printfc ├── make.sh ├── printfc.hh ├── printfc.dsw ├── test.cxx ├── README.md └── printfc.dsp ├── Mylog ├── make.sh ├── Log.cxx ├── main.cxx ├── mylog.vcproj └── Log.hh ├── Task ├── task.h ├── utils.h ├── utils.cpp ├── make.sh ├── thread.h ├── thread.cpp ├── types.h ├── Makefile ├── main.cpp ├── README.md ├── mutex.h └── task.cpp ├── CIniFile ├── Test │ ├── TestIniFile.exe │ ├── stdafx.cpp │ ├── stdafx.h │ └── TestIniFile.cpp ├── IniFile.h ├── README.md └── IniFile.cpp ├── Heartbeat ├── test │ ├── make.sh │ ├── server.cxx │ └── client.cxx ├── Heartbeat.vcproj ├── Heartbeat.hh └── Heartbeat.cxx ├── .gitignore ├── README.md └── optionparser-1.4 ├── src ├── printUsage.h ├── testodr2.cc ├── testodr1.cc ├── Makefile ├── example.cpp ├── example_arg.cc ├── testprintusage.cpp └── testparse.cpp ├── README.md ├── README_ARGC_ARGV ├── README.md.html └── DoxygenLayout.xml /printfc/make.sh: -------------------------------------------------------------------------------- 1 | gcc -o printfc test.cxx 2 | -------------------------------------------------------------------------------- /Mylog/make.sh: -------------------------------------------------------------------------------- 1 | g++ -o mylog main.cxx Log.cxx -lstdc++ -lpthread -I./ 2 | -------------------------------------------------------------------------------- /Task/task.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/js2854/CppUtile/HEAD/Task/task.h -------------------------------------------------------------------------------- /Mylog/Log.cxx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/js2854/CppUtile/HEAD/Mylog/Log.cxx -------------------------------------------------------------------------------- /Task/utils.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/js2854/CppUtile/HEAD/Task/utils.h -------------------------------------------------------------------------------- /Task/utils.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/js2854/CppUtile/HEAD/Task/utils.cpp -------------------------------------------------------------------------------- /printfc/printfc.hh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/js2854/CppUtile/HEAD/printfc/printfc.hh -------------------------------------------------------------------------------- /Task/make.sh: -------------------------------------------------------------------------------- 1 | g++ -o demo_task main.cpp thread.cpp task.cpp utils.cpp -I. -lrt -lpthread 2 | -------------------------------------------------------------------------------- /printfc/printfc.dsw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/js2854/CppUtile/HEAD/printfc/printfc.dsw -------------------------------------------------------------------------------- /CIniFile/Test/TestIniFile.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/js2854/CppUtile/HEAD/CIniFile/Test/TestIniFile.exe -------------------------------------------------------------------------------- /Heartbeat/test/make.sh: -------------------------------------------------------------------------------- 1 | g++ -o client client.cxx ../Heartbeat.cxx -lpthread 2 | g++ -o server server.cxx ../Heartbeat.cxx -lpthread -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | *.dylib 9 | 10 | # Compiled Static libraries 11 | *.lai 12 | *.la 13 | *.a 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #CppUtile 2 | 3 | 存放一些常用的C++类 4 | 5 | - Heartbeat 6 | - IniFile读写类 7 | - Log日志文件类(线程安全,跨windows&linux平台, 日志自动切换,可设置自动清理日志文件) 8 | - printfc -- printf with color 控制台多彩终端的实现(跨windows&linux平台) 9 | - Task调度框架, 仿照Darwin Streaming Server中的Task机制实现 10 | - optionparser命令行参数解析类,从sourceforge导入 11 | -------------------------------------------------------------------------------- /Heartbeat/test/server.cxx: -------------------------------------------------------------------------------- 1 | #include "../Heartbeat.hh" 2 | #include 3 | 4 | int main() 5 | { 6 | Heartbeat hb; 7 | hb.init(HB_SERVER); 8 | hb.run(); 9 | 10 | while (getchar() != 'q') 11 | { 12 | #ifdef WIN32 13 | Sleep(100); 14 | #else 15 | usleep(100*1000); 16 | #endif 17 | } 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /CIniFile/Test/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // TestIniFile.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /optionparser-1.4/src/printUsage.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * @brief Dummy file for documentation purposes. 4 | */ 5 | 6 | /** 7 | * @brief @ref option::printUsage() formats the usage message with column alignment and line wrapping. 8 | */ 9 | class UsageMsg{ 10 | // Dummy file to get an entry for printUsage() in Classes. 11 | }; 12 | -------------------------------------------------------------------------------- /CIniFile/Test/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | 9 | #include 10 | #include 11 | 12 | 13 | // TODO: reference additional headers your program requires here 14 | -------------------------------------------------------------------------------- /Heartbeat/test/client.cxx: -------------------------------------------------------------------------------- 1 | #include "../Heartbeat.hh" 2 | #include 3 | 4 | int main() 5 | { 6 | Heartbeat hb; 7 | hb.init(HB_CLIENT); 8 | hb.send_msg(HB_MSG_REG, NULL, 0); 9 | hb.run(); 10 | 11 | while (getchar() != 'q') 12 | { 13 | #ifdef WIN32 14 | Sleep(100); 15 | #else 16 | usleep(100*1000); 17 | #endif 18 | } 19 | 20 | hb.send_msg(HB_MSG_QUIT, NULL, 0); 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /Task/thread.h: -------------------------------------------------------------------------------- 1 | #ifndef __THREAD_H__ 2 | #define __THREAD_H__ 3 | 4 | #include 5 | #include 6 | #include "types.h" 7 | 8 | class Thread 9 | { 10 | public: 11 | Thread() : m_tid(-1), m_bStop(false) {} 12 | virtual ~Thread(); 13 | 14 | SInt32 Start(); 15 | void Stop() { m_bStop = true; } 16 | bool IsStop() { return m_bStop; } 17 | 18 | static void* ThreadEntry(void* i_pArg); 19 | 20 | virtual void Entry() = 0; 21 | 22 | SInt32 ThreadYield(); 23 | protected: 24 | pthread_t m_tid; 25 | bool m_bStop; 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /Task/thread.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "thread.h" 6 | 7 | Thread::~Thread() 8 | { 9 | void* pRetVal = NULL; 10 | SInt32 s32Ret = pthread_join(m_tid, &pRetVal); 11 | if (0 != s32Ret) 12 | { 13 | printf("pthread_join error! errno %d\n", errno); 14 | } 15 | } 16 | 17 | SInt32 Thread::Start() 18 | { 19 | SInt32 s32Ret = pthread_create(&m_tid, NULL, Thread::ThreadEntry, this); 20 | if (0 != s32Ret) 21 | { 22 | printf("pthread_create error! errno %d-%s\n", errno, strerror(errno)); 23 | } 24 | return s32Ret; 25 | } 26 | 27 | void* Thread::ThreadEntry(void* i_pArg) 28 | { 29 | Thread *pThread = (Thread*)i_pArg; 30 | pThread->Entry(); 31 | return NULL; 32 | } 33 | 34 | SInt32 Thread::ThreadYield() 35 | { 36 | return pthread_yield(); 37 | } 38 | -------------------------------------------------------------------------------- /printfc/test.cxx: -------------------------------------------------------------------------------- 1 | #include "printfc.hh" 2 | 3 | int main(void) 4 | { 5 | printfc(FG_RED, "red color text\n"); 6 | printfc(FG_GREEN, "green color text\n"); 7 | printfc(FG_YELLOW, "yellow color text\n"); 8 | printfc(FG_BLUE, "blue color text\n"); 9 | printfc(FG_PURPLE, "purple color text\n"); 10 | printfc(FG_DARKGREEN, "dark green color text\n"); 11 | printfc(FG_WHITE, "white color text\n\n"); 12 | 13 | printfc(FG_BLACK, BG_WHITE, "black color text on white"); 14 | printfc(FG_RED, BG_BLACK, "red color text on black\n"); 15 | printfc(FG_GREEN, BG_YELLOW, "green color text on yellow\n"); 16 | printfc(FG_YELLOW, BG_BLUE, "yellow color text on blue\n"); 17 | printfc(FG_BLUE, BG_WHITE, "blue color text\n on white\n"); 18 | printfc(FG_PURPLE, BG_WHITE, "purple color text\n on white\n"); 19 | printfc(FG_DARKGREEN, BG_DARKRED, "dark green color text\n on dark red\n"); 20 | printfc(FG_WHITE, BG_BLUE, "white color text\n on blue\n"); 21 | 22 | puts("\nPress any key to continue..."); 23 | getchar(); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /Task/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_H__ 2 | #define __TYPES_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | #ifdef DEBUG 15 | #include 16 | #include 17 | #define TRACE(fmt, ...) printf("[Time:%d]" fmt " -- [%s:%d]\n", (int)time(NULL), ## __VA_ARGS__, __FILE__, __LINE__) 18 | #else 19 | #define TRACE(fmt, ...) 20 | #endif 21 | 22 | typedef signed char SInt8; 23 | typedef unsigned char UInt8; 24 | typedef signed short SInt16; 25 | typedef unsigned short UInt16; 26 | typedef signed int SInt32; 27 | typedef unsigned int UInt32; 28 | typedef signed long long SInt64; 29 | typedef unsigned long long UInt64; 30 | 31 | typedef vector UInt32Vector; 32 | typedef vector StringVector; 33 | typedef map StringMap; 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /Task/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = bin/demo_task 2 | INC_DIR = . #inc 3 | SRC_DIR = . #src 4 | OBJ_DIR = obj 5 | 6 | CFLAGS = -Wall 7 | LDFLAGS = -lpthread -lrt 8 | 9 | SRCS = $(foreach DIR, ${SRC_DIR}, $(wildcard ${DIR}/*.cpp)) 10 | INCS = $(addprefix -I, ${INC_DIR}) 11 | OBJS = $(patsubst %.cpp, ${OBJ_DIR}/%.o, ${SRCS}) 12 | DEPS = $(patsubst ${OBJ_DIR}/%.o, ${OBJ_DIR}/%.dep, ${OBJS}) 13 | 14 | BIN_DIR = $(dir ${TARGET}) 15 | OBJS_SUBDIR = $(dir $(firstword ${OBJS})) 16 | 17 | CC = g++ 18 | LD = g++ 19 | 20 | .PHONY: all clean 21 | 22 | all: ${TARGET} 23 | 24 | debug: CFLAGS += -g -DDEBUG 25 | debug: ${TARGET} 26 | release: ${TARGET} 27 | 28 | mkdirs: 29 | test -d ${BIN_DIR} || mkdir -p ${BIN_DIR} 30 | test -d ${OBJS_SUBDIR} || mkdir -p ${OBJS_SUBDIR} 31 | 32 | ${TARGET}: mkdirs ${OBJS} 33 | ${LD} ${LDFLAGS} -o $@ ${OBJS} 34 | @echo -e "\n Build '$(TARGET)' success!\n" 35 | 36 | ${OBJ_DIR}/%.o: %.cpp 37 | ${CC} ${CFLAGS} ${INCS} -MMD -MP -MF$(@:%.o=%.dep) -MT$@ -o $@ -c $< 38 | 39 | clean: 40 | rm -rf ${TARGET} ${OBJ_DIR} 41 | @echo -e "\n clean complete!\n" 42 | 43 | -include ${DEPS} 44 | -------------------------------------------------------------------------------- /optionparser-1.4/src/testodr2.cc: -------------------------------------------------------------------------------- 1 | /* Written 2012 by Matthias S. Benkmann 2 | * 3 | * The author hereby waives all copyright and related rights to the contents 4 | * of this example file (testodr2.cc) to the extent possible under the law. 5 | */ 6 | 7 | /** 8 | * @file 9 | * @brief Test for multiple definition errors. 10 | * @copydoc testodr1.cc 11 | */ 12 | 13 | #include "optionparser.h" 14 | 15 | #include 16 | 17 | using option::Descriptor; 18 | using option::Arg; 19 | enum OptionIndex {CREATE}; 20 | enum OptionType {DISABLE, ENABLE, OTHER}; 21 | 22 | extern const Descriptor usage[] = { 23 | { CREATE, OTHER, 24 | "c", "create", 25 | Arg::None, 26 | "--create\t\t\tTells the program to create something." 27 | } 28 | }; 29 | 30 | extern bool foo(int argc, const char* argv[]) 31 | { 32 | printUsage(std::fwrite, stdout, usage); 33 | option::Stats stats(usage, argc, argv); 34 | option::Option buffer [stats.buffer_max]; 35 | option::Option options[stats.options_max]; 36 | option::Parser parse(usage, argc, argv, options, buffer); 37 | return parse.error(); 38 | } 39 | 40 | -------------------------------------------------------------------------------- /printfc/README.md: -------------------------------------------------------------------------------- 1 | #printfc -- printf with color 2 | 3 | 控制台多彩终端 4 | 5 | - 跨Linux && Windows平台 6 | - 对Linux平台下换行的情况作了处理 7 | 8 | ## 使用示例 9 | 10 | **由于公司代码加密, 因此头文件是.hh后缀,源文件是.cxx后缀** 11 | 12 | #include "printfc.hh" 13 | 14 | int main(void) 15 | { 16 | printfc(FG_RED, "red color text\n"); 17 | printfc(FG_GREEN, "green color text\n"); 18 | printfc(FG_YELLOW, "yellow color text\n"); 19 | printfc(FG_BLUE, "blue color text\n"); 20 | printfc(FG_PURPLE, "purple color text\n"); 21 | printfc(FG_DARKGREEN, "dark green color text\n"); 22 | printfc(FG_WHITE, "white color text\n\n"); 23 | 24 | printfc(FG_BLACK, BG_WHITE, "black color text on white"); 25 | printfc(FG_RED, BG_BLACK, "red color text on black\n"); 26 | printfc(FG_GREEN, BG_YELLOW, "green color text on yellow\n"); 27 | printfc(FG_YELLOW, BG_BLUE, "yellow color text on blue\n"); 28 | printfc(FG_BLUE, BG_WHITE, "blue color text\n on white\n"); 29 | printfc(FG_PURPLE, BG_WHITE, "purple color text\n on white\n"); 30 | printfc(FG_DARKGREEN, BG_DARKRED, "dark green color text\n on dark red\n"); 31 | printfc(FG_WHITE, BG_BLUE, "white color text\n on blue\n"); 32 | 33 | puts("\nPress any key to continue..."); 34 | getchar(); 35 | return 0; 36 | } 37 | 38 | ## 效果图 39 | 40 | ![效果图](http://ww2.sinaimg.cn/large/468527aagw1edvk042mssj20au0bxmy3.jpg "") 41 | -------------------------------------------------------------------------------- /Task/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "task.h" 4 | #include "utils.h" 5 | 6 | class PrintTask : public Task 7 | { 8 | public: 9 | PrintTask() : Task() {} 10 | void Init() 11 | { 12 | PushEvents(Task::kStartEvent); 13 | } 14 | SInt64 Run() 15 | { 16 | EventFlags events = PopEvents(); 17 | if (events & kStartEvent) 18 | { 19 | printf("PrintTask: kStartEvent\n"); 20 | } 21 | if (events & kTimeoutEvent) 22 | { 23 | printf("PrintTask: kTimeoutEvent\n"); 24 | } 25 | if (events & kIdleEvent) 26 | { 27 | printf("PrintTask: kIdleEvent, %llu ms\n", MilliSeconds()); 28 | } 29 | 30 | if (events & kKillEvent) 31 | { 32 | printf("PrintTask: kKillEvent, kill myself\n"); 33 | return -1; 34 | } 35 | 36 | return 1*1000; 37 | } 38 | }; 39 | 40 | int main(int argc, char *argv[]) 41 | { 42 | TaskThreadPool::AddThreads(1); 43 | 44 | PrintTask *pTask = new PrintTask(); 45 | pTask->Init(); 46 | 47 | SleepUs(5*1000*1000);// sleep 5s 48 | 49 | printf("main: send kill event\n"); 50 | pTask->PushEvents(Task::kKillEvent); 51 | pTask = NULL; 52 | 53 | SleepUs(1*1000*1000);// sleep 1s 54 | TaskThreadPool::RemoveThreads(); 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /optionparser-1.4/src/testodr1.cc: -------------------------------------------------------------------------------- 1 | /* Written 2012 by Matthias S. Benkmann 2 | * 3 | * The author hereby waives all copyright and related rights to the contents 4 | * of this example file (testodr1.cc) to the extent possible under the law. 5 | */ 6 | 7 | /** 8 | * @file 9 | * @brief Test for multiple definition errors. 10 | * 11 | * @note 12 | * This program is for developing TLMC++OP. It is neither an example nor a functionality test. 13 | * Do not worry if it doesn't compile or run on your platform. 14 | * 15 | * @ref testodr1.cc and @ref testodr2.cc test optionparser.h for 16 | * violations of the one definition rule, both at compile-time and at 17 | * link-time. IOW, they test if optionparser.h can be included 18 | * multiple times as well as that multiple object files that include 19 | * it can be linked together. 20 | * 21 | */ 22 | 23 | #include "optionparser.h" 24 | #include "optionparser.h" //intentionally included twice 25 | 26 | #include 27 | 28 | using option::Option; 29 | using option::Descriptor; 30 | 31 | extern const Descriptor usage[]; 32 | 33 | extern bool bar(int argc, const char* argv[]) 34 | { 35 | printUsage(std::fwrite, stdout, usage); 36 | option::Stats stats(usage, argc, argv); 37 | option::Option buffer [stats.buffer_max]; 38 | option::Option options[stats.options_max]; 39 | option::Parser parse(usage, argc, argv, options, buffer); 40 | return parse.error(); 41 | } 42 | 43 | int main() 44 | { 45 | Descriptor d = usage[0]; 46 | std::printf("%s",d.shortopt); 47 | } 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /optionparser-1.4/README.md: -------------------------------------------------------------------------------- 1 | # C++ Option Parser 2 | 3 | import project from sourceforge [optionparser](https://sourceforge.net/projects/optionparser/) 4 | 5 | Documentation is [here](http://optionparser.sourceforge.net/) 6 | 7 | 8 | ## Example 9 | 10 | #include 11 | #include "optionparser.h" 12 | 13 | enum optionIndex { UNKNOWN, HELP, PLUS }; 14 | const option::Descriptor usage[] = 15 | { 16 | {UNKNOWN, 0,"" , "" ,option::Arg::None, "USAGE: example [options]\n\n" 17 | "Options:" }, 18 | {HELP, 0,"" , "help",option::Arg::None, " --help \tPrint usage and exit." }, 19 | {PLUS, 0,"p", "plus",option::Arg::None, " --plus, -p \tIncrement count." }, 20 | {UNKNOWN, 0,"" , "" ,option::Arg::None, "\nExamples:\n" 21 | " example --unknown -- --this_is_no_option\n" 22 | " example -unk --plus -ppp file1 file2\n" }, 23 | {0,0,0,0,0,0} 24 | }; 25 | 26 | int main(int argc, char* argv[]) 27 | { 28 | argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present 29 | option::Stats stats(usage, argc, argv); 30 | option::Option options[stats.options_max], buffer[stats.buffer_max]; 31 | option::Parser parse(usage, argc, argv, options, buffer); 32 | 33 | if (parse.error()) 34 | return 1; 35 | 36 | if (options[HELP] || argc == 0) 37 | { 38 | option::printUsage(std::cout, usage); 39 | return 0; 40 | } 41 | 42 | std::cout << "--plus count: " << options[PLUS].count() << "\n"; 43 | 44 | for (option::Option* opt = options[UNKNOWN]; opt; opt = opt->next()) 45 | std::cout << "Unknown option: " << opt->name << "\n"; 46 | 47 | for (int i = 0; i < parse.nonOptionsCount(); ++i) 48 | std::cout << "Non-option #" << i << ": " << parse.nonOption(i) << "\n"; 49 | } 50 | -------------------------------------------------------------------------------- /optionparser-1.4/src/Makefile: -------------------------------------------------------------------------------- 1 | CXX=g++ 2 | CXXFLAGS=-W -Wall -g -fmessage-length=0 3 | CCFLAGS=$(CXXFLAGS) -fno-exceptions -fno-rtti -nodefaultlibs 4 | OPTIMIZE=-Os -fomit-frame-pointer 5 | #OPTIMIZE=-O0 6 | LD=gcc # gcc automatically picks the correct crt*.o and helper libraries to link 7 | VERSION=1.4 8 | PACKAGEDIR=optionparser-$(VERSION) 9 | TARBALL=../$(PACKAGEDIR).tar.gz 10 | 11 | all: example_arg testparse testprintusage testodr example doc 12 | 13 | # .cpp files depend on the C++ standard lib 14 | %: %.cpp optionparser.h 15 | $(CXX) $(CXXFLAGS) $(OPTIMIZE) -o $@ $< 16 | 17 | # .cc files depend only on libc 18 | %.o: %.cc optionparser.h 19 | $(CXX) $(CCFLAGS) $(OPTIMIZE) -c $< 20 | 21 | %: %.cc optionparser.h 22 | $(CXX) $(CCFLAGS) $(OPTIMIZE) -lc -o $@ $< 23 | 24 | testprintusage: testprintusage.cpp optionparser.h 25 | $(CXX) $(CXXFLAGS) $(OPTIMIZE) -Wno-unused-result -o $@ $< 26 | 27 | # testodr needs to be linked in a separate step rather than 28 | # just passing both .cpp files to g++, because only this way 29 | # can we be sure that duplicate definitions cause an error message. 30 | testodr: testodr1.o testodr2.o 31 | $(LD) -lc -o $@ $^ 32 | 33 | doc: 34 | cd .. && doxygen 35 | cd .. && cat Doxyfile | sed '/^INTERNAL_DOCS/s/YES/NO/;/^HTML_OUTPUT/s/-dev//' | doxygen - 36 | 37 | clean: 38 | rm -f testodr testodr1.o testodr2.o example.o example testprintusage testparse example_arg 39 | rm -rf ../html ../html-dev $(PACKAGEDIR) $(TARBALL) 40 | rm -f *~ ../*~ 41 | 42 | package: 43 | rm -rf $(PACKAGEDIR) 44 | mkdir -p $(PACKAGEDIR)/src 45 | cp ../Doxyfile ../DoxygenLayout.xml ../README_ARGC_ARGV $(PACKAGEDIR) 46 | cp Makefile example.cpp example_arg.cc optionparser.h \ 47 | testodr1.cc testodr2.cc testparse.cpp testprintusage.cpp \ 48 | printUsage.h $(PACKAGEDIR)/src 49 | tar --owner=0 --group=0 -czf $(TARBALL) $(PACKAGEDIR) 50 | 51 | upload: all package 52 | cd .. && scp -r src/optionparser.h html/* optionparser-frs:/home/project-web/optionparser/htdocs 53 | scp $(TARBALL) optionparser-frs:/home/frs/project/o/op/optionparser 54 | -------------------------------------------------------------------------------- /optionparser-1.4/src/example.cpp: -------------------------------------------------------------------------------- 1 | /* Written 2012 by Matthias S. Benkmann 2 | * 3 | * The author hereby waives all copyright and related rights to the contents 4 | * of this example file (example.cpp) to the extent possible under the law. 5 | */ 6 | 7 | /** 8 | * @file 9 | * @brief Small demo of The Lean Mean C++ Option Parser. 10 | * 11 | * @include example.cpp 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include "optionparser.h" 18 | 19 | enum optionIndex { UNKNOWN, HELP, PLUS }; 20 | const option::Descriptor usage[] = 21 | { 22 | {UNKNOWN, 0, "", "",option::Arg::None, "USAGE: example [options]\n\n" 23 | "Options:" }, 24 | {HELP, 0,"", "help",option::Arg::None, " --help \tPrint usage and exit." }, 25 | {PLUS, 0,"p","plus",option::Arg::None, " --plus, -p \tIncrement count." }, 26 | {UNKNOWN, 0, "", "",option::Arg::None, "\nExamples:\n" 27 | " example --unknown -- --this_is_no_option\n" 28 | " example -unk --plus -ppp file1 file2\n" }, 29 | {0,0,0,0,0,0} 30 | }; 31 | 32 | int main(int argc, char* argv[]) 33 | { 34 | argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present 35 | option::Stats stats(usage, argc, argv); 36 | std::vector options(stats.options_max); 37 | std::vector buffer(stats.buffer_max); 38 | option::Parser parse(usage, argc, argv, &options[0], &buffer[0]); 39 | 40 | if (parse.error()) 41 | return 1; 42 | 43 | if (options[HELP] || argc == 0) { 44 | option::printUsage(std::cout, usage); 45 | return 0; 46 | } 47 | 48 | std::cout << "--plus count: " << 49 | options[PLUS].count() << "\n"; 50 | 51 | for (option::Option* opt = options[UNKNOWN]; opt; opt = opt->next()) 52 | std::cout << "Unknown option: " << std::string(opt->name,opt->namelen) << "\n"; 53 | 54 | for (int i = 0; i < parse.nonOptionsCount(); ++i) 55 | std::cout << "Non-option #" << i << ": " << parse.nonOption(i) << "\n"; 56 | } 57 | -------------------------------------------------------------------------------- /Task/README.md: -------------------------------------------------------------------------------- 1 | ## Task 2 | 3 | 简单的Task调度框架,仿照Darwin Streaming Server中的Task机制实现 4 | 5 | 6 | ## Demo 7 | 8 | #include 9 | #include 10 | #include "task.h" 11 | #include "utils.h" 12 | 13 | class PrintTask : public Task 14 | { 15 | public: 16 | PrintTask() : Task() {} 17 | void Init() 18 | { 19 | Signal(Task::kStartEvent); 20 | } 21 | SInt64 Run() 22 | { 23 | EventFlags events = GetEvents(); 24 | if (events & kStartEvent) 25 | { 26 | printf("PrintTask: kStartEvent\n"); 27 | } 28 | if (events & kTimeoutEvent) 29 | { 30 | printf("PrintTask: kTimeoutEvent\n"); 31 | } 32 | if (events & kIdleEvent) 33 | { 34 | printf("PrintTask: kIdleEvent, %llu ms\n", MilliSeconds()); 35 | } 36 | 37 | if (events & kKillEvent) 38 | { 39 | printf("PrintTask: kKillEvent, kill myself\n"); 40 | return -1; 41 | } 42 | 43 | return 1*1000; 44 | } 45 | }; 46 | 47 | int main(int argc, char *argv[]) 48 | { 49 | TaskThreadPool::AddThreads(2); 50 | 51 | PrintTask *pTask = new PrintTask(); 52 | pTask->Init(); 53 | 54 | SleepUs(5*1000*1000);// sleep 5s 55 | 56 | printf("main: send kill event\n"); 57 | pTask->Signal(Task::kKillEvent); 58 | pTask = NULL; 59 | 60 | SleepUs(1*1000*1000);// sleep 1s 61 | TaskThreadPool::RemoveThreads(); 62 | 63 | return 0; 64 | } 65 | 66 | 67 | ### Result 68 | 69 | [root@zmsstest Task]# ./demo_task 70 | PrintTask: kStartEvent 71 | PrintTask: kIdleEvent, 14926901778 ms 72 | PrintTask: kIdleEvent, 14926902779 ms 73 | PrintTask: kIdleEvent, 14926903780 ms 74 | PrintTask: kIdleEvent, 14926904780 ms 75 | PrintTask: kIdleEvent, 14926905781 ms 76 | main: send kill event 77 | PrintTask: kIdleEvent, 14926906781 ms 78 | PrintTask: kKillEvent, kill myself 79 | -------------------------------------------------------------------------------- /optionparser-1.4/README_ARGC_ARGV: -------------------------------------------------------------------------------- 1 | POSIX Guidelines for command line arguments 2 | 3 | http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html 4 | 5 | ---------------------------------------------- 6 | 7 | From the C standard: 8 | 9 | 5.1.2.2.1 Program startup 10 | 11 | The function called at program startup is named main. The implementation declares no 12 | prototype for this function. It shall be defined with a return type of int and with no 13 | parameters: 14 | 15 | int main(void) { /* ... */ } 16 | 17 | or with two parameters (referred to here as argc and argv, though any names may be 18 | used, as they are local to the function in which they are declared): 19 | 20 | int main(int argc, char *argv[]) { /* ... */ } 21 | 22 | or equivalent; or in some other implementation-defined manner. 23 | 24 | If they are declared, the parameters to the main function shall obey the following 25 | constraints: 26 | 27 | — The value of argc shall be nonnegative. 28 | 29 | — argv[argc] shall be a null pointer. 30 | 31 | — If the value of argc is greater than zero, the array members argv[0] through 32 | argv[argc-1] inclusive shall contain pointers to strings, which are given 33 | implementation-defined values by the host environment prior to program startup. 34 | The intent is to supply to the program information determined prior to program 35 | startup from elsewhere in the hosted environment. If the host environment is 36 | not capable of supplying strings with letters in both uppercase and lowercase, 37 | the implementation shall ensure that the strings are received in lowercase. 38 | 39 | — If the value of argc is greater than zero, the string pointed to by argv[0] 40 | represents the program name; argv[0][0] shall be the null character if the 41 | program name is not available from the host environment. If the value of argc is 42 | greater than one, the strings pointed to by argv[1] through argv[argc-1] 43 | represent the program parameters. 44 | 45 | — The parameters argc and argv and the strings pointed to by the argv array shall 46 | be modifiable by the program, and retain their last-stored values between program 47 | startup and program termination. 48 | 49 | -------------------------------------------------------------------------------- /Task/mutex.h: -------------------------------------------------------------------------------- 1 | #ifndef __MUTEX_H__ 2 | #define __MUTEX_H__ 3 | 4 | #include 5 | #include 6 | #include "utils.h" 7 | 8 | typedef pthread_mutex_t mutex_t; 9 | typedef pthread_condattr_t condattr_t; 10 | typedef pthread_cond_t cond_t; 11 | 12 | class Mutex 13 | { 14 | public: 15 | Mutex(void) { pthread_mutex_init(&m_lock, NULL); } 16 | virtual ~Mutex(void) { pthread_mutex_destroy(&m_lock); } 17 | inline void Lock() { pthread_mutex_lock(&m_lock); } 18 | inline void Unlock() { pthread_mutex_unlock(&m_lock); } 19 | mutex_t& GetMutex() { return m_lock; } 20 | private: 21 | mutex_t m_lock; 22 | }; 23 | 24 | 25 | class AutoMutex 26 | { 27 | public: 28 | AutoMutex(Mutex *i_pMutex) : m_pMutex(i_pMutex) { m_pMutex->Lock(); } 29 | virtual ~AutoMutex(void) { m_pMutex->Unlock(); } 30 | private: 31 | Mutex *m_pMutex; 32 | }; 33 | 34 | class Cond 35 | { 36 | public: 37 | Cond() 38 | { 39 | condattr_t attr; 40 | pthread_condattr_init(&attr); 41 | pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); 42 | pthread_cond_init(&m_cond, &attr); 43 | } 44 | ~Cond() {} 45 | 46 | inline void Signal() 47 | { 48 | assert(0 == pthread_cond_signal(&m_cond)); 49 | } 50 | inline UInt32 Wait(Mutex &i_Mutex, SInt32 i_s32TimeoutMs = 0) 51 | { 52 | SInt32 s32Ret = 0; 53 | if (i_s32TimeoutMs > 0) 54 | { 55 | UInt64 u64CurTime = Nanoseconds(); 56 | UInt64 u64ns = u64CurTime + (UInt64)i_s32TimeoutMs * NS_IN_1MS; 57 | struct timespec ts; 58 | ts.tv_sec = u64ns / NS_IN_1SEC; 59 | ts.tv_nsec = u64ns % NS_IN_1SEC; 60 | s32Ret = pthread_cond_timedwait(&m_cond, &i_Mutex.GetMutex(), &ts); 61 | } 62 | else 63 | { 64 | s32Ret = pthread_cond_wait(&m_cond, &i_Mutex.GetMutex()); 65 | } 66 | return s32Ret; 67 | } 68 | inline void Broadcast() 69 | { 70 | assert(0 == pthread_cond_broadcast(&m_cond)); 71 | } 72 | private: 73 | cond_t m_cond; 74 | }; 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /optionparser-1.4/README.md.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | README 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |

C++ Option Parser

16 | 17 |

import project from sourceforge optionparser

18 | 19 |

Documentation is here

20 | 21 |

Example

22 | 23 |
#include <iostream>
24 | #include "optionparser.h"
25 | 
26 | enum  optionIndex { UNKNOWN, HELP, PLUS };
27 | const option::Descriptor usage[] =
28 | {
29 |     {UNKNOWN, 0,"" , ""    ,option::Arg::None, "USAGE: example [options]\n\n"
30 |                                             "Options:" },
31 |     {HELP,    0,"" , "help",option::Arg::None, "  --help  \tPrint usage and exit." },
32 |     {PLUS,    0,"p", "plus",option::Arg::None, "  --plus, -p  \tIncrement count." },
33 |     {UNKNOWN, 0,"" ,  ""   ,option::Arg::None, "\nExamples:\n"
34 |                                             "  example --unknown -- --this_is_no_option\n"
35 |                                             "  example -unk --plus -ppp file1 file2\n" },
36 |     {0,0,0,0,0,0}
37 | };
38 | 
39 | int main(int argc, char* argv[])
40 | {
41 |     argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present
42 |     option::Stats  stats(usage, argc, argv);
43 |     option::Option options[stats.options_max], buffer[stats.buffer_max];
44 |     option::Parser parse(usage, argc, argv, options, buffer);
45 | 
46 |     if (parse.error())
47 |         return 1;
48 | 
49 |     if (options[HELP] || argc == 0)
50 |     {
51 |         option::printUsage(std::cout, usage);
52 |         return 0;
53 |     }
54 | 
55 |     std::cout << "--plus count: " << options[PLUS].count() << "\n";
56 | 
57 |     for (option::Option* opt = options[UNKNOWN]; opt; opt = opt->next())
58 |         std::cout << "Unknown option: " << opt->name << "\n";
59 | 
60 |     for (int i = 0; i < parse.nonOptionsCount(); ++i)
61 |         std::cout << "Non-option #" << i << ": " << parse.nonOption(i) << "\n";
62 | }
63 | 
64 | 72 | 73 | -------------------------------------------------------------------------------- /Mylog/main.cxx: -------------------------------------------------------------------------------- 1 | #include //clock_t,clock(),CLOCKS_PER_SEC 2 | 3 | #ifdef WIN32 4 | #include //_beginthread 5 | #else 6 | #include //pthread_create 7 | #endif 8 | 9 | 10 | #include "Log.hh" 11 | 12 | #ifdef SINGLE_LOG 13 | int main() 14 | { 15 | #ifdef linux 16 | SET_LOG_NAME("/home/jaxon/some_test/mylog/temp/test.log"); 17 | #else 18 | SET_LOG_NAME("C:\\test\\test.log"); 19 | #endif 20 | //设置日志级别 21 | SET_LOG_LEVEL(LOG_LEVEL_TRACE); 22 | 23 | //设置日志大小 24 | SET_LOG_SIZE(10 * 1024 * 1024); 25 | 26 | //设置占用磁盘空间大小 27 | SET_LOG_SPACE(100 * 1024 * 1024); 28 | 29 | clock_t start, finish; 30 | double duration; 31 | 32 | start = clock(); 33 | 34 | for(int i = 0; i < 1000000; i++) 35 | { 36 | LOG_TRACE("****%d****", i); 37 | LOG_INFO("test INFO"); 38 | LOG_WARNING("test WARNING"); 39 | LOG_ERROR("test ERROR"); 40 | } 41 | 42 | finish = clock(); 43 | duration = (double)(finish - start) / CLOCKS_PER_SEC; 44 | printf("duration = %.3f.\n", duration); 45 | 46 | getchar(); 47 | 48 | return 0; 49 | } 50 | 51 | #else 52 | 53 | //需要用户在此定义模块名有宏 54 | //e.g. 55 | #define TESTMODULE1 "TestModule1" 56 | #define TESTMODULE2 "TestModule2" 57 | 58 | #ifdef WIN32 59 | void threadfunc(void *param) 60 | #else 61 | void* threadfunc(void *param) 62 | #endif 63 | { 64 | clock_t start, finish; 65 | double duration; 66 | char* pstr = (char*)param; 67 | 68 | start = clock(); 69 | 70 | for(int i = 0; i < 100000; i++) 71 | { 72 | LOG_TRACE(pstr, "%s ****%d****", pstr, i); 73 | LOG_INFO(pstr, "%s test INFO", pstr); 74 | LOG_WARNING(pstr, "%s test WARNING", pstr); 75 | LOG_ERROR(pstr, "%s test ERROR", pstr); 76 | } 77 | 78 | finish = clock(); 79 | duration = (double)(finish - start) / CLOCKS_PER_SEC; 80 | printf("duration = %.3f.\n", duration); 81 | 82 | fflush(stdout); 83 | } 84 | 85 | int main() 86 | { 87 | #ifdef linux 88 | SET_LOG_NAME(TESTMODULE1, "/home/jaxon/some_test/mylog/temp/test1.log"); 89 | SET_LOG_NAME(TESTMODULE2, "/home/jaxon/some_test/mylog/temp/test2.log"); 90 | #else 91 | SET_LOG_NAME(TESTMODULE1, "C:\\test\\test1.log"); 92 | SET_LOG_NAME(TESTMODULE2, "C:\\test\\test2.log"); 93 | #endif 94 | //设置日志级别 95 | SET_LOG_LEVEL(TESTMODULE1, LOG_LEVEL_TRACE); 96 | SET_LOG_LEVEL(TESTMODULE2, LOG_LEVEL_TRACE); 97 | 98 | //设置日志大小 99 | SET_LOG_SIZE(TESTMODULE1, 1 * 1024 * 1024); 100 | SET_LOG_SIZE(TESTMODULE2, 1 * 1024 * 1024); 101 | 102 | //设置占用磁盘空间大小 103 | SET_LOG_SPACE(TESTMODULE1, 10 * 1024 * 1024); 104 | SET_LOG_SPACE(TESTMODULE2, 10 * 1024 * 1024); 105 | 106 | #ifdef WIN32 107 | _beginthread(threadfunc, NULL, TESTMODULE1); 108 | _beginthread(threadfunc, NULL, TESTMODULE2); 109 | #else 110 | pthread_t handle1 = 0; 111 | pthread_t handle2 = 0; 112 | int ret = pthread_create(&handle1, (pthread_attr_t*)0, threadfunc, (void*)TESTMODULE1); 113 | printf("create thread 1. ret = %d, handle=%d\n", ret, handle1); 114 | ret = pthread_create(&handle2, (pthread_attr_t*)0, threadfunc, (void*)TESTMODULE2); 115 | printf("create thread 2. ret = %d, handle=%d\n", ret, handle2); 116 | #endif 117 | 118 | getchar(); 119 | 120 | return 0; 121 | } 122 | #endif 123 | -------------------------------------------------------------------------------- /CIniFile/IniFile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | class CIniFile 11 | { 12 | public: 13 | struct Record 14 | { 15 | string Comments; 16 | char Commented; 17 | string Section; 18 | string Key; 19 | string Value; 20 | }; 21 | 22 | enum CommentChar 23 | { 24 | Pound = '#', 25 | SemiColon = ';' 26 | }; 27 | 28 | CIniFile(void); 29 | virtual ~CIniFile(void); 30 | 31 | static bool AddSection(string SectionName, string FileName); 32 | static bool CommentRecord(CommentChar cc, string KeyName,string SectionName,string FileName); 33 | static bool CommentSection(char CommentChar, string SectionName, string FileName); 34 | static string Content(string FileName); 35 | static bool Create(string FileName); 36 | static bool DeleteRecord(string KeyName, string SectionName, string FileName); 37 | static bool DeleteSection(string SectionName, string FileName); 38 | static vector GetRecord(string KeyName, string SectionName, string FileName); 39 | static vector GetSection(string SectionName, string FileName); 40 | static vector GetSectionNames(string FileName); 41 | static string GetValue(string KeyName, string SectionName, string FileName); 42 | static bool RecordExists(string KeyName, string SectionName, string FileName); 43 | static bool RenameSection(string OldSectionName, string NewSectionName, string FileName); 44 | static bool SectionExists(string SectionName, string FileName); 45 | static bool SetRecordComments(string Comments, string KeyName, string SectionName, string FileName); 46 | static bool SetSectionComments(string Comments, string SectionName, string FileName); 47 | static bool SetValue(string KeyName, string Value, string SectionName, string FileName); 48 | static bool Sort(string FileName, bool Descending); 49 | static bool UnCommentRecord(string KeyName,string SectionName,string FileName); 50 | static bool UnCommentSection(string SectionName, string FileName); 51 | 52 | private: 53 | static vector GetSections(string FileName); 54 | static bool Load(string FileName, vector& content); 55 | static bool Save(string FileName, vector& content); 56 | 57 | struct RecordSectionIs : std::unary_function 58 | { 59 | std::string section_; 60 | 61 | RecordSectionIs(const std::string& section): section_(section){} 62 | 63 | bool operator()( const Record& rec ) const 64 | { 65 | return rec.Section == section_; 66 | } 67 | }; 68 | 69 | struct RecordSectionKeyIs : std::unary_function 70 | { 71 | std::string section_; 72 | std::string key_; 73 | 74 | RecordSectionKeyIs(const std::string& section, const std::string& key): section_(section),key_(key){} 75 | 76 | bool operator()( const Record& rec ) const 77 | { 78 | return ((rec.Section == section_)&&(rec.Key == key_)); 79 | } 80 | }; 81 | 82 | struct AscendingSectionSort 83 | { 84 | bool operator()(Record& Start, Record& End) 85 | { 86 | return Start.Section < End.Section; 87 | } 88 | }; 89 | 90 | struct DescendingSectionSort 91 | { 92 | bool operator()(Record& Start, Record& End) 93 | { 94 | return Start.Section > End.Section; 95 | } 96 | }; 97 | 98 | struct AscendingRecordSort 99 | { 100 | bool operator()(Record& Start, Record& End) 101 | { 102 | return Start.Key < End.Key; 103 | } 104 | }; 105 | 106 | struct DescendingRecordSort 107 | { 108 | bool operator()(Record& Start, Record& End) 109 | { 110 | return Start.Key > End.Key; 111 | } 112 | }; 113 | }; -------------------------------------------------------------------------------- /printfc/printfc.dsp: -------------------------------------------------------------------------------- 1 | # Microsoft Developer Studio Project File - Name="printfc" - Package Owner=<4> 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Console Application" 0x0103 6 | 7 | CFG=printfc - Win32 Debug 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "printfc.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "printfc.mak" CFG="printfc - Win32 Debug" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "printfc - Win32 Release" (based on "Win32 (x86) Console Application") 21 | !MESSAGE "printfc - Win32 Debug" (based on "Win32 (x86) Console Application") 22 | !MESSAGE 23 | 24 | # Begin Project 25 | # PROP AllowPerConfigDependencies 0 26 | # PROP Scc_ProjName "" 27 | # PROP Scc_LocalPath "" 28 | CPP=cl.exe 29 | RSC=rc.exe 30 | 31 | !IF "$(CFG)" == "printfc - Win32 Release" 32 | 33 | # PROP BASE Use_MFC 0 34 | # PROP BASE Use_Debug_Libraries 0 35 | # PROP BASE Output_Dir "Release" 36 | # PROP BASE Intermediate_Dir "Release" 37 | # PROP BASE Target_Dir "" 38 | # PROP Use_MFC 0 39 | # PROP Use_Debug_Libraries 0 40 | # PROP Output_Dir "Release" 41 | # PROP Intermediate_Dir "Release" 42 | # PROP Target_Dir "" 43 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c 44 | # ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c 45 | # ADD BASE RSC /l 0x804 /d "NDEBUG" 46 | # ADD RSC /l 0x804 /d "NDEBUG" 47 | BSC32=bscmake.exe 48 | # ADD BASE BSC32 /nologo 49 | # ADD BSC32 /nologo 50 | LINK32=link.exe 51 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 52 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 53 | 54 | !ELSEIF "$(CFG)" == "printfc - Win32 Debug" 55 | 56 | # PROP BASE Use_MFC 0 57 | # PROP BASE Use_Debug_Libraries 1 58 | # PROP BASE Output_Dir "Debug" 59 | # PROP BASE Intermediate_Dir "Debug" 60 | # PROP BASE Target_Dir "" 61 | # PROP Use_MFC 0 62 | # PROP Use_Debug_Libraries 1 63 | # PROP Output_Dir "Debug" 64 | # PROP Intermediate_Dir "Debug" 65 | # PROP Target_Dir "" 66 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c 67 | # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c 68 | # ADD BASE RSC /l 0x804 /d "_DEBUG" 69 | # ADD RSC /l 0x804 /d "_DEBUG" 70 | BSC32=bscmake.exe 71 | # ADD BASE BSC32 /nologo 72 | # ADD BSC32 /nologo 73 | LINK32=link.exe 74 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept 75 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept 76 | 77 | !ENDIF 78 | 79 | # Begin Target 80 | 81 | # Name "printfc - Win32 Release" 82 | # Name "printfc - Win32 Debug" 83 | # Begin Group "Source Files" 84 | 85 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 86 | # Begin Source File 87 | 88 | SOURCE=.\test.cxx 89 | # End Source File 90 | # End Group 91 | # Begin Group "Header Files" 92 | 93 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 94 | # End Group 95 | # Begin Group "Resource Files" 96 | 97 | # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" 98 | # End Group 99 | # Begin Source File 100 | 101 | SOURCE=.\printfc.hh 102 | # End Source File 103 | # End Target 104 | # End Project 105 | -------------------------------------------------------------------------------- /Mylog/mylog.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 52 | 55 | 58 | 61 | 68 | 71 | 74 | 77 | 80 | 83 | 86 | 89 | 90 | 98 | 101 | 104 | 107 | 110 | 113 | 124 | 127 | 130 | 133 | 142 | 145 | 148 | 151 | 154 | 157 | 160 | 163 | 164 | 165 | 166 | 167 | 168 | 173 | 176 | 177 | 180 | 181 | 182 | 187 | 190 | 191 | 192 | 197 | 198 | 199 | 200 | 201 | 202 | -------------------------------------------------------------------------------- /Heartbeat/Heartbeat.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 52 | 55 | 58 | 61 | 68 | 71 | 74 | 77 | 80 | 83 | 86 | 89 | 90 | 98 | 101 | 104 | 107 | 110 | 113 | 124 | 127 | 130 | 133 | 142 | 145 | 148 | 151 | 154 | 157 | 160 | 163 | 164 | 165 | 166 | 167 | 168 | 173 | 176 | 177 | 180 | 181 | 184 | 185 | 186 | 191 | 192 | 197 | 198 | 201 | 202 | 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /Task/task.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "task.h" 3 | #include "utils.h" 4 | 5 | #define MIN_WAIT_TIME_MS 10 6 | #define MAX_RUN_TIMES_ONCE 10 7 | 8 | UInt32 TaskThreadPool::m_u32ThreadNum = 0; 9 | UInt32 TaskThreadPool::m_u32ThreadPicker = 0; 10 | ThreadVector TaskThreadPool::m_vecThreads; 11 | 12 | void Task::PushEvents(Task::EventFlags i_Events, SInt64 i_Priority) 13 | { 14 | m_Events |= i_Events; 15 | TRACE("0.PushEvents: Task %p, i_Events %d, i_Priority %lld, IsAlive %d, ThreadNum %d", 16 | this, i_Events, i_Priority, IsAlive() ? 1 : 0, TaskThreadPool::GetThreadNum()); 17 | if (IsAlive() && TaskThreadPool::GetThreadNum() > 0) 18 | { 19 | TRACE("1.PushEvents: Task %p, i_Events %d, i_Priority %lld", this, i_Events, i_Priority); 20 | TaskThreadPool::AddTask(this, i_Priority); 21 | TRACE("2.PushEvents: Task %p, i_Events %d, i_Priority %lld", this, i_Events, i_Priority); 22 | } 23 | } 24 | 25 | Task::EventFlags Task::PopEvents() 26 | { 27 | Task::EventFlags events = m_Events; 28 | m_Events -= events; 29 | return events; 30 | } 31 | 32 | TaskThread::~TaskThread() 33 | { 34 | Stop(); 35 | AutoMutex mutex(&m_lock); 36 | while (!m_TaskQueue.empty()) 37 | { 38 | m_TaskQueue.pop(); 39 | } 40 | m_TaskSet.clear(); 41 | while (!m_TimeoutTaskQueue.empty()) 42 | { 43 | m_TimeoutTaskQueue.pop(); 44 | } 45 | } 46 | 47 | void TaskThread::Entry() 48 | { 49 | while (!IsStop()) 50 | { 51 | Task *pTask = WaitForTask(); 52 | if (NULL == pTask || IsStop()) 53 | { 54 | break; 55 | } 56 | TRACE("GetTask %p", pTask); 57 | SInt32 s32MaxRunTimes = MAX_RUN_TIMES_ONCE; 58 | while (s32MaxRunTimes-- > 0 && pTask->IsAlive() && pTask->GetEvents() > 0) 59 | { 60 | SInt64 ret = pTask->Run(); 61 | if (ret > 0) 62 | { 63 | s32MaxRunTimes = 0; 64 | pTask->PushEvents(Task::kIdleEvent, ret); 65 | } 66 | else if (ret < 0) 67 | { 68 | s32MaxRunTimes = 0; 69 | delete pTask; 70 | pTask = NULL; 71 | } 72 | ThreadYield(); 73 | } 74 | } 75 | } 76 | 77 | void TaskThread::AddTask(Task* i_pTask, SInt64 i_Priority) 78 | { 79 | if (i_Priority > 0) 80 | { 81 | i_Priority = i_Priority*US_IN_1MS + MicroSeconds(); 82 | T_Node n(i_Priority, i_pTask); 83 | AutoMutex mutex(&m_lock); 84 | m_TimeoutTaskQueue.push(n); 85 | } 86 | else if (m_TaskSet.find(i_pTask) == m_TaskSet.end()) 87 | { 88 | { 89 | AutoMutex mutex(&m_lock); 90 | m_TaskQueue.push(i_pTask); 91 | m_TaskSet.insert(i_pTask); 92 | } 93 | m_cond.Signal(); 94 | } 95 | TRACE("AddTask: pTask %p, Time %lld", i_pTask, i_Priority); 96 | } 97 | 98 | Task* TaskThread::WaitForTask() 99 | { 100 | while (!IsStop()) 101 | { 102 | UInt64 u64CurTime = MicroSeconds(); 103 | if (!m_TimeoutTaskQueue.empty() && m_TimeoutTaskQueue.top().u64Priority <= u64CurTime) 104 | { 105 | AutoMutex mutex(&m_lock); 106 | const T_Node &n = m_TimeoutTaskQueue.top(); 107 | Task* pTask = (Task*)n.pValue; 108 | m_TimeoutTaskQueue.pop(); 109 | return pTask; 110 | } 111 | else 112 | { 113 | AutoMutex mutex(&m_lock); 114 | if (m_TaskQueue.empty()) 115 | { 116 | UInt64 u64Timeout = 0; 117 | if (!m_TimeoutTaskQueue.empty()) 118 | { 119 | u64Timeout = (m_TimeoutTaskQueue.top().u64Priority - u64CurTime)/US_IN_1MS; 120 | } 121 | u64Timeout = std::max((UInt64)MIN_WAIT_TIME_MS, u64Timeout); 122 | // TRACE("wait %llu ms", u64Timeout); 123 | m_cond.Wait(m_lock, u64Timeout); 124 | // TRACE("wait timeout"); 125 | } 126 | if (!m_TaskQueue.empty()) 127 | { 128 | Task* pTask = m_TaskQueue.front(); 129 | m_TaskQueue.pop(); 130 | m_TaskSet.erase(pTask); 131 | return pTask; 132 | } 133 | } 134 | ThreadYield(); 135 | } 136 | 137 | return NULL; 138 | } 139 | 140 | void TaskThreadPool::AddThreads(UInt32 i_u32Num) 141 | { 142 | if (m_vecThreads.empty()) 143 | { 144 | m_u32ThreadNum = i_u32Num; 145 | for (UInt32 i = 0; i < i_u32Num; i ++) 146 | { 147 | TaskThread *pThread = new TaskThread(); 148 | m_vecThreads.push_back(pThread); 149 | pThread->Start(); 150 | } 151 | } 152 | } 153 | 154 | void TaskThreadPool::RemoveThreads() 155 | { 156 | ThreadVector::iterator it = m_vecThreads.begin(); 157 | for (; it != m_vecThreads.end(); it++) 158 | { 159 | TaskThread *pThread = *it; 160 | delete pThread; 161 | pThread = NULL; 162 | } 163 | m_vecThreads.clear(); 164 | } 165 | 166 | void TaskThreadPool::AddTask(Task* i_pTask, SInt64 i_Priority) 167 | { 168 | UInt32 u32Idx = (++m_u32ThreadPicker) % m_u32ThreadNum; 169 | TaskThread *pThread = m_vecThreads[u32Idx]; 170 | if (pThread && !pThread->IsStop()) 171 | { 172 | pThread->AddTask(i_pTask, i_Priority); 173 | } 174 | } 175 | 176 | 177 | -------------------------------------------------------------------------------- /Heartbeat/Heartbeat.hh: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * 3 | * 文件名称:Heartbeat.hh 4 | * 摘 要:跨Windows和Linux平台的Heartbeat类 5 | * 6 | * 当前版本:0.1 7 | * 作 者:Jaxon Jia 8 | * 创建日期:2013/07/24 9 | * 10 | **********************************************************************/ 11 | #ifndef __Heartbeat_h__ 12 | #define __Heartbeat_h__ 13 | 14 | #include 15 | #include 16 | #include // for memset 17 | #include 18 | #include 19 | #include 20 | #include 21 | using std::vector; 22 | 23 | #ifdef WIN32 24 | #include // for _begainthread() 25 | #include 26 | #include // for inet_pton 27 | #pragma comment(lib, "ws2_32.lib") 28 | #else 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #endif 37 | 38 | #define HB_VERSION "0.1" 39 | 40 | #define HB_MAX_NODE_COUNT 100 41 | #define HB_INTERVAL_SLEEP 1000 42 | #define HB_DEFAULT_PORT 8000 43 | #define HB_DEFAULT_IP "127.0.0.1" 44 | #define HB_TOLERANCE 4 // default is 4s 45 | 46 | #define HB_IP_LEN 40 // define max ip len is 40byte 47 | #define HB_NODE_DESCRIPT 50 // max length of node descript text 48 | #define HB_BUF_SIZE 1024 // socket recv or send buffer size 49 | 50 | #define TRACE(format, ...) printf("[%s]"format"\n", __FUNCTION__, ##__VA_ARGS__) 51 | #define MIN(a,b) (((a)<(b))?(a):(b)) 52 | #define MAX(a,b) (((a)>(b))?(a):(b)) 53 | 54 | enum 55 | { 56 | HB_ERR_SOCK_INIT = -100, 57 | HB_ERR_SOCK_BIND, 58 | HB_ERR_SOCK_SETOPT, 59 | HB_ERR_SOCK_SEND, 60 | HB_ERR_SOCK_RECV, 61 | HB_ERR_INVALID_PARAM, 62 | HB_OK = 0 63 | }; 64 | 65 | typedef enum 66 | { 67 | HB_CLIENT = 0, 68 | HB_SERVER 69 | }HBRUNTYPE; 70 | 71 | typedef enum 72 | { 73 | HB_MSG_REG = 0, // register to server or controller 74 | HB_MSG_RUNNING, // running, heartbeat message 75 | HB_MSG_QUIT, // client quit message 76 | HB_MSG_ERR, // run error 77 | 78 | }HBMSGTYPE; 79 | 80 | typedef struct 81 | { 82 | HBMSGTYPE type; // message type 83 | time_t timestamp; // current time 84 | u_int len; // msg length 85 | char content[1]; // message content 86 | }HBMSG; 87 | 88 | typedef struct 89 | { 90 | char ip[HB_IP_LEN]; // node ip 91 | u_int port; // node port 92 | time_t timestamp; // node latest timestamp 93 | u_int islive; // 1 live, 0 dead 94 | void* descript; // node other info 95 | }NODE; 96 | 97 | class Heartbeat 98 | { 99 | public: 100 | Heartbeat(void); 101 | Heartbeat(HBRUNTYPE hb_type, const char* ip, u_int port=HB_DEFAULT_PORT, u_int interval=HB_INTERVAL_SLEEP, u_int tolerance=HB_TOLERANCE); 102 | ~Heartbeat(void); 103 | 104 | public: 105 | /********************************************************************* 106 | * 函数名称: init 107 | * 函数描述: 初始化 108 | * 参 数: 109 | * [IN]ip const char * IP地址 110 | * [IN]port u_int 端口 111 | * [IN]interval u_int 发送心跳包的间隔 112 | * [IN]tolerance u_int 心跳超时间隔时间 113 | * 返 回 值: N/A 114 | * 创建日期: 2013/07/24 115 | *********************************************************************/ 116 | void init(HBRUNTYPE hb_type, const char* ip=HB_DEFAULT_IP, u_int port=HB_DEFAULT_PORT, u_int interval=HB_INTERVAL_SLEEP, u_int tolerance=HB_TOLERANCE); 117 | 118 | /********************************************************************* 119 | * 函数名称: send_msg 120 | * 函数描述: 消息发送函数 121 | * 参 数: 122 | * [IN]type HBMSGTYPE 消息类型 123 | * [IN]content const char * 消息内容 124 | * [IN]len u_int 消息内容的长度 125 | * 返 回 值: 发送成功返回0,否则返回负值 126 | * 创建日期: 2013/07/24 127 | *********************************************************************/ 128 | int send_msg(HBMSGTYPE type, const char* content, u_int len); 129 | 130 | /********************************************************************* 131 | * 函数名称: run 132 | * 函数描述: 作为Heartbeat客户端或服务端运行 133 | * 参 数: N/A 134 | * 返 回 值: N/A 135 | * 创建日期: 2013/07/25 136 | *********************************************************************/ 137 | int run(); 138 | 139 | /********************************************************************* 140 | * 函数名称: callback 141 | * 函数描述: 心跳线程回调函数 142 | * 参 数: 143 | * [IN]msg HBMSG * 发送或接收到的消息 144 | * [IN]src_sin sockaddr_in 发送或接收的IP,Port信息 145 | * 返 回 值: N/A 146 | * 创建日期: 2013/07/25 147 | *********************************************************************/ 148 | virtual void* callback(HBMSG* msg=NULL, sockaddr_in* src_sin=NULL); 149 | 150 | /********************************************************************* 151 | * 函数名称: as_server 152 | * 函数描述: 作为服务端运行时的心跳线程函数, as_client和as_server互斥 153 | * 参 数: N/A 154 | * 返 回 值: N/A 155 | * 创建日期: 2013/07/25 156 | *********************************************************************/ 157 | virtual int as_server(); 158 | 159 | /********************************************************************* 160 | * 函数名称: as_client 161 | * 函数描述: 作为客户端运行时的心跳线程函数, as_client和as_server互斥 162 | * 参 数: N/A 163 | * 返 回 值: N/A 164 | * 创建日期: 2013/07/25 165 | *********************************************************************/ 166 | virtual int as_client(); 167 | 168 | private: 169 | time_t cur_time(); 170 | int init_sock(); 171 | void mysleep(u_int ms); 172 | int closesock(int sock); 173 | #ifdef WIN32 174 | static void threadfunc(void *param); 175 | int new_thread(void (*func)(void*), void *param); 176 | #else 177 | static void* threadfunc(void *param); 178 | int new_thread(void* (*func)(void*), void *param); 179 | #endif 180 | 181 | int m_sock; 182 | HBRUNTYPE m_hb_type; // run as client or server 183 | char m_ip[HB_IP_LEN]; // Destination ip address, default is 127.0.0.1. 184 | u_int m_port; // Listen or send socket port 185 | u_int m_interval; // The interval in milliseconds between heartbeat message, default is 1000 (1 second). 186 | u_int m_tolerance; // The number of seconds before reporting that the node is dead, default is 4s. 187 | vector node_list; 188 | }; 189 | 190 | #endif // __Heartbeat_h__ 191 | 192 | -------------------------------------------------------------------------------- /optionparser-1.4/src/example_arg.cc: -------------------------------------------------------------------------------- 1 | /* Written 2012 by Matthias S. Benkmann 2 | * 3 | * The author hereby waives all copyright and related rights to the contents 4 | * of this example file (example_arg.cc) to the extent possible under the law. 5 | */ 6 | 7 | /** 8 | * @file 9 | * @brief Demonstrates handling various types of option arguments (required, numeric,...) with 10 | no dependency on the C++ standard library (only C lib). 11 | * 12 | * @include example_arg.cc 13 | */ 14 | 15 | #include 16 | #include 17 | #include "optionparser.h" 18 | 19 | struct Arg: public option::Arg 20 | { 21 | static void printError(const char* msg1, const option::Option& opt, const char* msg2) 22 | { 23 | fprintf(stderr, "%s", msg1); 24 | fwrite(opt.name, opt.namelen, 1, stderr); 25 | fprintf(stderr, "%s", msg2); 26 | } 27 | 28 | static option::ArgStatus Unknown(const option::Option& option, bool msg) 29 | { 30 | if (msg) printError("Unknown option '", option, "'\n"); 31 | return option::ARG_ILLEGAL; 32 | } 33 | 34 | static option::ArgStatus Required(const option::Option& option, bool msg) 35 | { 36 | if (option.arg != 0) 37 | return option::ARG_OK; 38 | 39 | if (msg) printError("Option '", option, "' requires an argument\n"); 40 | return option::ARG_ILLEGAL; 41 | } 42 | 43 | static option::ArgStatus NonEmpty(const option::Option& option, bool msg) 44 | { 45 | if (option.arg != 0 && option.arg[0] != 0) 46 | return option::ARG_OK; 47 | 48 | if (msg) printError("Option '", option, "' requires a non-empty argument\n"); 49 | return option::ARG_ILLEGAL; 50 | } 51 | 52 | static option::ArgStatus Numeric(const option::Option& option, bool msg) 53 | { 54 | char* endptr = 0; 55 | if (option.arg != 0 && strtol(option.arg, &endptr, 10)){}; 56 | if (endptr != option.arg && *endptr == 0) 57 | return option::ARG_OK; 58 | 59 | if (msg) printError("Option '", option, "' requires a numeric argument\n"); 60 | return option::ARG_ILLEGAL; 61 | } 62 | }; 63 | 64 | enum optionIndex { UNKNOWN, HELP, OPTIONAL, REQUIRED, NUMERIC, NONEMPTY }; 65 | const option::Descriptor usage[] = { 66 | { UNKNOWN, 0,"", "", Arg::Unknown, "USAGE: example_arg [options]\n\n" 67 | "Options:" }, 68 | { HELP, 0,"", "help", Arg::None, " \t--help \tPrint usage and exit." }, 69 | { OPTIONAL,0,"o","optional",Arg::Optional," -o[], \t--optional[=]" 70 | " \tTakes an argument but is happy without one." }, 71 | { REQUIRED,0,"r","required",Arg::Required," -r , \t--required= \tMust have an argument." }, 72 | { NUMERIC, 0,"n","numeric", Arg::Numeric, " -n , \t--numeric= \tRequires a number as argument." }, 73 | { NONEMPTY,0,"1","nonempty",Arg::NonEmpty," -1 , \t--nonempty=" 74 | " \tCan NOT take the empty string as argument." }, 75 | { UNKNOWN, 0,"", "", Arg::None, 76 | "\nExamples:\n" 77 | " example_arg --unknown -o -n10 \n" 78 | " example_arg -o -n10 file1 file2 \n" 79 | " example_arg -nfoo file1 file2 \n" 80 | " example_arg --optional -- file1 file2 \n" 81 | " example_arg --optional file1 file2 \n" 82 | " example_arg --optional=file1 file2 \n" 83 | " example_arg --optional= file1 file2 \n" 84 | " example_arg -o file1 file2 \n" 85 | " example_arg -ofile1 file2 \n" 86 | " example_arg -unk file1 file2 \n" 87 | " example_arg -r -- file1 \n" 88 | " example_arg -r file1 \n" 89 | " example_arg --required \n" 90 | " example_arg --required=file1 \n" 91 | " example_arg --nonempty= file1 \n" 92 | " example_arg --nonempty=foo --numeric=999 --optional=bla file1 \n" 93 | " example_arg -1foo \n" 94 | " example_arg -1 -- \n" 95 | " example_arg -1 \"\" \n" 96 | }, 97 | { 0, 0, 0, 0, 0, 0 } }; 98 | 99 | int main(int argc, char* argv[]) 100 | { 101 | argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present 102 | option::Stats stats(usage, argc, argv); 103 | 104 | #ifdef __GNUC__ 105 | // GCC supports C99 VLAs for C++ with proper constructor calls. 106 | option::Option options[stats.options_max], buffer[stats.buffer_max]; 107 | #else 108 | // use calloc() to allocate 0-initialized memory. It's not the same 109 | // as properly constructed elements, but good enough. Obviously in an 110 | // ordinary C++ program you'd use new[], but this file demonstrates that 111 | // TLMC++OP can be used without any dependency on the C++ standard library. 112 | option::Option* options = (option::Option*)calloc(stats.options_max, sizeof(option::Option)); 113 | option::Option* buffer = (option::Option*)calloc(stats.buffer_max, sizeof(option::Option)); 114 | #endif 115 | 116 | option::Parser parse(usage, argc, argv, options, buffer); 117 | 118 | if (parse.error()) 119 | return 1; 120 | 121 | if (options[HELP] || argc == 0) 122 | { 123 | int columns = getenv("COLUMNS")? atoi(getenv("COLUMNS")) : 80; 124 | option::printUsage(fwrite, stdout, usage, columns); 125 | return 0; 126 | } 127 | 128 | for (int i = 0; i < parse.optionsCount(); ++i) 129 | { 130 | option::Option& opt = buffer[i]; 131 | fprintf(stdout, "Argument #%d is ", i); 132 | switch (opt.index()) 133 | { 134 | case HELP: 135 | // not possible, because handled further above and exits the program 136 | case OPTIONAL: 137 | if (opt.arg) 138 | fprintf(stdout, "--optional with optional argument '%s'\n", opt.arg); 139 | else 140 | fprintf(stdout, "--optional without the optional argument\n"); 141 | break; 142 | case REQUIRED: 143 | fprintf(stdout, "--required with argument '%s'\n", opt.arg); 144 | break; 145 | case NUMERIC: 146 | fprintf(stdout, "--numeric with argument '%s'\n", opt.arg); 147 | break; 148 | case NONEMPTY: 149 | fprintf(stdout, "--nonempty with argument '%s'\n", opt.arg); 150 | break; 151 | case UNKNOWN: 152 | // not possible because Arg::Unknown returns ARG_ILLEGAL 153 | // which aborts the parse with an error 154 | break; 155 | } 156 | } 157 | 158 | for (int i = 0; i < parse.nonOptionsCount(); ++i) 159 | fprintf(stdout, "Non-option argument #%d is %s\n", i, parse.nonOption(i)); 160 | } 161 | -------------------------------------------------------------------------------- /optionparser-1.4/DoxygenLayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /Mylog/Log.hh: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Filename: Log.hh 3 | * Abstract: Log Class corss-platform(linux and windows) 4 | * 5 | * Version : 0.1 6 | * Author : js2854 7 | * Date : 2013/09/03 8 | **********************************************************************/ 9 | #ifndef __Log_h__ 10 | #define __Log_h__ 11 | 12 | #include 13 | #include 14 | #include 15 | using namespace std; 16 | 17 | //#define SINGLE_LOG 18 | 19 | #ifdef SINGLE_LOG 20 | //单实例API 21 | #define DEFAULT_MODULE "DEFAULT" 22 | #define SET_LOG_NAME(filepath) CLogFactory::get_instance(DEFAULT_MODULE)->set_log_filepath(filepath) 23 | #define SET_LOG_LEVEL(level) CLogFactory::get_instance(DEFAULT_MODULE)->set_log_level(level) 24 | #define SET_LOG_SIZE(size) CLogFactory::get_instance(DEFAULT_MODULE)->set_log_size(size) 25 | #define SET_LOG_SPACE(size) CLogFactory::get_instance(DEFAULT_MODULE)->set_log_space(size) 26 | 27 | #define LOG_TRACE(format, ...) CLogFactory::get_instance(DEFAULT_MODULE)->writeline(LOG_LEVEL_TRACE, format, ## __VA_ARGS__) 28 | #define LOG_INFO(format, ...) CLogFactory::get_instance(DEFAULT_MODULE)->writeline(LOG_LEVEL_INFO, format, ## __VA_ARGS__) 29 | #define LOG_WARNING(format, ...) CLogFactory::get_instance(DEFAULT_MODULE)->writeline(LOG_LEVEL_WARNING, format, ## __VA_ARGS__) 30 | #define LOG_ERROR(format, ...) CLogFactory::get_instance(DEFAULT_MODULE)->writeline(LOG_LEVEL_ERROR, format, ## __VA_ARGS__) 31 | 32 | #else 33 | 34 | //多实例API 35 | #define SET_LOG_NAME(module, filepath) CLogFactory::get_instance(module)->set_log_filepath(filepath) 36 | #define SET_LOG_LEVEL(module, level) CLogFactory::get_instance(module)->set_log_level(level) 37 | #define SET_LOG_SIZE(module, size) CLogFactory::get_instance(module)->set_log_size(size) 38 | #define SET_LOG_SPACE(module, size) CLogFactory::get_instance(module)->set_log_space(size) 39 | 40 | #define LOG_TRACE(module, format, ...) CLogFactory::get_instance(module)->writeline(LOG_LEVEL_TRACE, format, ## __VA_ARGS__) 41 | #define LOG_INFO(module, format, ...) CLogFactory::get_instance(module)->writeline(LOG_LEVEL_INFO, format, ## __VA_ARGS__) 42 | #define LOG_WARNING(module, format, ...) CLogFactory::get_instance(module)->writeline(LOG_LEVEL_WARNING, format, ## __VA_ARGS__) 43 | #define LOG_ERROR(module, format, ...) CLogFactory::get_instance(module)->writeline(LOG_LEVEL_ERROR, format, ## __VA_ARGS__) 44 | 45 | #endif 46 | 47 | //日志级别 48 | enum _log_level 49 | { 50 | LOG_LEVEL_ERROR = 1, //错误 51 | LOG_LEVEL_WARNING = 2, //警告 52 | LOG_LEVEL_INFO = 3, //普通 53 | LOG_LEVEL_TRACE = 4, //调试 54 | LOG_LEVEL_MAX 55 | }; 56 | 57 | #ifndef __MY_LOCK__ 58 | #define __MY_LOCK__ 59 | 60 | #ifdef WIN32 61 | #include 62 | #else 63 | #include 64 | #endif 65 | 66 | class MutexLock 67 | { 68 | #ifdef WIN32 69 | private: 70 | CRITICAL_SECTION m_lock; 71 | public: 72 | MutexLock(void) {InitializeCriticalSection(&m_lock);} 73 | virtual ~MutexLock(void) {DeleteCriticalSection(&m_lock);} 74 | void lock() {EnterCriticalSection(&m_lock);} 75 | void unlock() {LeaveCriticalSection(&m_lock);} 76 | #else 77 | private: 78 | pthread_mutex_t m_lock; 79 | public: 80 | MutexLock(void) {pthread_mutex_init(&m_lock, NULL);} 81 | virtual ~MutexLock(void) {pthread_mutex_destroy(&m_lock);} 82 | void lock() {pthread_mutex_lock(&m_lock);} 83 | void unlock() {pthread_mutex_unlock(&m_lock);} 84 | #endif 85 | }; 86 | #endif //__MY_LOCK__ 87 | 88 | typedef unsigned int uint; 89 | typedef unsigned long uint32; 90 | 91 | #ifdef _WIN32 92 | typedef unsigned __int64 uint64; 93 | #else 94 | typedef unsigned long long uint64; 95 | #endif 96 | 97 | #define MAX_TIME_STR_LEN 30 98 | 99 | typedef struct 100 | { 101 | string file_path; //文件路径 102 | uint64 size; //文件大小 103 | time_t mtime; //修改时间 104 | }file_info; 105 | 106 | typedef vector file_list; 107 | 108 | class CLog 109 | { 110 | public: 111 | CLog(void); 112 | ~CLog(void); 113 | 114 | //设置日志文件路径 115 | void set_log_filepath(const string filepath) {m_log_filename = filepath; mk_dir(); rotate_log();} 116 | 117 | //设置日志文件大小切换, 单位byte 118 | void set_log_size(uint size) {m_log_size = size;} 119 | 120 | //设置日志文件占用磁盘空间大小, 单位byte 121 | void set_log_space(uint64 size) {m_max_log_space = size;} 122 | 123 | //设置日志级别 124 | void set_log_level(uint level) {m_log_level = (level > LOG_LEVEL_MAX) ? LOG_LEVEL_MAX : level;} 125 | 126 | //设置日志清理状态 127 | void set_clean_status(bool status) {m_lock.lock(); m_is_cleaning = status; m_lock.unlock();} 128 | 129 | string& get_log_path() {return m_log_filename;} 130 | uint64 get_max_space() {return m_max_log_space;} 131 | 132 | //写入一行日志 133 | int writeline(uint level, const char* format_str, ...); 134 | 135 | private: 136 | void rotate_log(); //日志切换 137 | bool mk_dir(); //检查目录是否存在,不存在的话循环创建 138 | char* get_time_str(bool is_write=true); //获取当前时间字符串 139 | bool rename_file(); //取当前时间重命名日志文件 140 | int get_thread_id(); //获取当前进程id 141 | void clean_logs(); //清理日志文件 142 | 143 | //日志文件清理线程 144 | #ifdef WIN32 145 | static void clean_logs_thread_fun(void* param); 146 | #else 147 | static void* clean_logs_thread_fun(void* param); 148 | #endif 149 | 150 | //根据日志文件名获取相关日志列表 151 | static bool get_log_files(const string& log_path, file_list& files); 152 | //根据日志文件名获取日志目录(末尾带有'\'或'/') 153 | static string get_log_dir(const string& log_path); 154 | 155 | private: 156 | MutexLock m_lock; //同步锁,用于多线程同步写 157 | string m_log_filename; //日志文件路径名 158 | FILE* m_fp; //日志文件句柄 159 | uint m_log_level; //设置的日志级别 160 | uint m_log_size; //设置的日志文件大小 161 | uint64 m_max_log_space; //设置日志文件占用磁盘空间大小 162 | bool m_is_cleaning; //是否正在进行日志清理 163 | 164 | char m_time_str[MAX_TIME_STR_LEN]; //时间字符串buf 165 | }; 166 | 167 | #define MAX_LOG_INSTANCE 10 168 | #define MAX_MODULE_LEN 30 169 | 170 | typedef struct _log_instance 171 | { 172 | char name[MAX_MODULE_LEN]; 173 | CLog* plog; 174 | }log_inst; 175 | 176 | class CLogFactory 177 | { 178 | public: 179 | CLogFactory(void); 180 | virtual ~CLogFactory(void); 181 | 182 | static CLog* get_instance(const char* name); 183 | static void free_instance(const char* name); 184 | 185 | private: 186 | static void free_all_inst(); 187 | 188 | private: 189 | static log_inst m_inst_list[MAX_LOG_INSTANCE]; //log实例列表 190 | static uint m_inst_num; //log实例数量 191 | static MutexLock m_lock; //同步锁 192 | }; 193 | 194 | #endif // __Log_h__ 195 | 196 | -------------------------------------------------------------------------------- /optionparser-1.4/src/testprintusage.cpp: -------------------------------------------------------------------------------- 1 | /* Written 2012 by Matthias S. Benkmann 2 | * 3 | * The author hereby waives all copyright and related rights to the contents 4 | * of this example file (testprintusage.cpp) to the extent possible under the law. 5 | */ 6 | 7 | /** 8 | * @file 9 | * @brief Test program for the option::printUsage() function. 10 | * 11 | * @note 12 | * This program is for developing TLMC++OP. It is neither an example nor a functionality test. 13 | * Do not worry if it doesn't compile or run on your platform. 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "optionparser.h" 22 | 23 | using namespace std; 24 | using option::Descriptor; 25 | using option::Arg; 26 | 27 | const Descriptor test_vtabs[] = { 28 | {0,0,"","",Arg::None, "Cölüümn 1 line ı\vColumn 1 line 2\vColumn 1 line 3 \t\vColumn 2 line 2 \tColumn 3 line 1\v\vColumn 3 line 3 "}, 29 | {0,0,0,0,0,0} 30 | }; 31 | 32 | const Descriptor test_columns[] = { 33 | {0,0,"","",Arg::None, "Column 1 line 1 \t\tColumn 3 line 1\n" 34 | "Column 1 line 2 \tColumn 2 line 2 \tColumn 3 line 2\n" 35 | "Column 1 line 3 \t\tColumn 3 line 3" }, 36 | {0,0,0,0,0,0} 37 | }; 38 | 39 | const Descriptor test_column1[] = { 40 | {0,0,"","",Arg::None, "11 \t21\v22\v23\t 31\nxx" }, 41 | {0,0,0,0,0,0} 42 | }; 43 | 44 | 45 | const Descriptor test_tables[] = { 46 | {0,0,"","",Arg::None,0}, // table break 47 | {0,0,"","",Arg::None,0}, // table break 48 | {0,0,"","",Arg::None, "Each table has its own column widths and is not aligned with other tables."}, 49 | {0,0,"","",Arg::None, "Table 1 Column 1 Line 1 \tTable 1 Column 2 Line 1 \tTable 1 Column 3 Line 1\n" 50 | "Table 1 Col 1 Line 2 \tTable 1 Col 2 Line 2 \tTable 1 Col 3 Line 2" 51 | }, 52 | {0,0,"","",Arg::None, "Table 1 Col 1 Line 3 \tTable 1 Col 2 Line 3 \tTable 1 Column 3 Line 3\n" 53 | "Table 1 Col 1 Line 4 \tTable 1 Column 2 Line 4 \tTable 1 Column 3 Line 4" 54 | }, 55 | {0,0,"","",Arg::None,0}, // table break 56 | {0,0,"","",Arg::None,0}, // table break 57 | {0,0,"","",Arg::None, "This is the only line of table 2." }, 58 | {0,0,"","",Arg::None,0}, // table break 59 | {0,0,"","",Arg::None, "This is the very long 1st line of table 3. It is more than 80 characters in length and therefore needs to be wrapped. In fact it is so long that it needs to be wrapped multiple times to fit into a normal 80 characters terminal.\v" 60 | "This is the very long 2nd line of table 3. It is more than 80 characters in length and therefore needs to be wrapped. In fact it is so long that it needs to be wrapped multiple times to fit into a normal 80 characters terminal.\v" 61 | "This is a reasonably sized line 3 of table 3." 62 | }, 63 | {0,0,"","",Arg::None,0}, // table break 64 | {0,0,"","",Arg::None, "Table 4:\n" 65 | " \tTable 4 C 1 L 1 \tTable 4 C 2 L 1 \tTable 4 C 3 L 1\n" 66 | "\tTable 4 C 1 L 2 \tTable 4 C 2 L 2 \tTable 4 C 3 L 2" 67 | }, 68 | {0,0,"","",Arg::None,0}, // table break 69 | {0,0,"","",Arg::None, "This is the only line of table 5"}, 70 | {0,0,"","",Arg::None,0}, // table break 71 | {0,0,"","",Arg::None, "Table 6 C 1 L 1 \tTable 6 C 2 L 1 \tTable 6 C 3 L 1\n" 72 | "Table 6 C 1 L 2 \tTable 6 C 2 L 2 \tTable 6 C 3 L 2" 73 | }, 74 | {0,0,"","",Arg::None,0 }, // table break 75 | {0,0,"","",Arg::None, "Table 7 Column 1 Line 1 \tTable 7 Column 2 Line 1 \tTable 7 Column 3 Line 1\n" 76 | "Table 7 Column 1 Line 2 \tTable 7 Column 2 Line 2 \tTable 7 Column 3 Line 2\n" 77 | }, 78 | {0,0,0,0,0,0} 79 | }; 80 | 81 | const Descriptor test_nohelp[] = { 82 | {0,0,"","",Arg::None, 0 }, 83 | {0,0,"","",Arg::None, 0 }, 84 | {0,0,"","",Arg::None, 0 }, 85 | {0,0,0,0,0,0} 86 | }; 87 | 88 | const Descriptor test_wide[] = { 89 | {0,0,"","",Arg::None, "Roma\t|x漢" }, 90 | {0,0,"","",Arg::None, "カタカナ\t|漢字" }, 91 | {0,0,"","",Arg::None, "漢字\t|漢カ " }, 92 | {0,0,"","",Arg::None, "漢字\t|カナ 漢字" }, 93 | {0,0,0,0,0,0} 94 | }; 95 | 96 | const Descriptor test_overlong[] = { 97 | {0,0,"","",Arg::None, "Good \t| Good \t| This is good." }, 98 | {0,0,"","",Arg::None, "Good \t| This is an overlong cell. \t| This is good." }, 99 | {0,0,"","",Arg::None, "Good \t| Good \t| This is good." }, 100 | {0,0,0,0,0,0} 101 | }; 102 | 103 | const Descriptor test_toomanycolumns[] = { 104 | {0,0,"","",Arg::None, "This \ttable \thas \ttoo \tmany \tcolumns. \tThe \tlast \tcolumns \tare \tdiscarded." }, 105 | {0,0,"","",Arg::None, "1\t2\t3\t4\t5\t6\t7\t8\t9\t10\t11" }, 106 | {0,0,0,0,0,0} 107 | }; 108 | 109 | const Descriptor test_ownline[] = { 110 | {0,0,"","",Arg::None, "1234567890AB\vBA0987654321\tStarts on its own line and is indented somewhat.\vThis one, too." }, 111 | {0,0,0,0,0,0} 112 | }; 113 | 114 | const Descriptor test_overflow[] = { 115 | {0,0,"","",Arg::None, "漢字漢字漢字漢字漢字漢字漢字漢字漢字漢字漢字漢字漢字漢字漢字漢字漢字漢字漢字漢字漢字" }, 116 | {0,0,0,0,0,0} 117 | }; 118 | 119 | void stderr_write(const char* str, int size) 120 | { 121 | fwrite(str, size, 1, stderr); 122 | } 123 | 124 | struct stderr_writer 125 | { 126 | void write(const char* buf, size_t size) const 127 | { 128 | ::write(2, buf, size); 129 | } 130 | }; 131 | 132 | struct stderr_write_functor 133 | { 134 | void operator()(const char* buf, size_t size) 135 | { 136 | ::write(2, buf, size); 137 | } 138 | }; 139 | 140 | int main() 141 | { 142 | fputs("---------------------------------------------------------------\n",stderr); 143 | option::printUsage(stderr_write, test_overflow, 1); 144 | fputs("---------------------------------------------------------------\n",stderr); 145 | option::printUsage(stderr_write, test_vtabs); 146 | fputs("---------------------------------------------------------------\n",stderr); 147 | option::printUsage(stderr_writer(), test_columns); 148 | fputs("---------------------------------------------------------------\n",stderr); 149 | option::printUsage(write, 2, test_column1); 150 | fputs("---------------------------------------------------------------\n",stderr); 151 | option::printUsage(cerr, test_tables); 152 | fputs("---------------------------------------------------------------\n",stderr); 153 | option::printUsage(fwrite, stderr, test_nohelp); 154 | fputs("---------------------------------------------------------------\n",stderr); 155 | ostringstream sst; 156 | option::printUsage(sst, test_wide, 8); 157 | cerr< 34 | .. 35 | // Create a new file called test.ini 36 | CIniFile::Create("test.ini"); 37 | // Create a Section called MySection, and a key/value of MyKey=MyValue 38 | CIniFile::SetValue("MyKey","MyValue","MySection",FileName); 39 | // Get the value of MyKey in section MySection and store it in s 40 | std::string s = CIniFile::GetValue("MyKey","MySection",FileName); 41 | // Sort the sections and records 42 | CIniFile::Sort("test.ini"); 43 | .. 44 | 45 | # Features # 46 | - Create, Rename, Edit and Delete Sections and Keys with ease 47 | - Comment and Uncomment Sections or Keys 48 | - Add comment lines (such as instructions) to any Section or Key 49 | - Sort entire files 50 | - Can handle multiple comment lines, and comments stay with their targets even through a sort 51 | - Retrieve Section Names 52 | - Retrieve file contents as a string 53 | - Verify that Sections and Keys exist 54 | 55 | # Limitations # 56 | There were a few features I really wanted to add to this class that aren't there yet. First, be aware that this class is case sensitive! I wanted to add an option to ignore case, but was having a tough time implementing it smoothly. My initial solution was to read in the file and convert it all to uppercase for comparison, but this then saved out the file as all uppercase. If you can figure out a way to make it work smoothly, please let me know. 57 | 58 | Another option I really wanted to add was the ability to convert INI files to/from XML. While I could technically add this to some degree, it would have either taken an enormous amount of coding on my part, or dependence on another class or library. In the interests of keeping this class cross platform friendly and easily distributable, I decided not to include this feature. If you like, you can probably throw this in using TinyXML or a similar XML parser. Then again, if you are using INI files, then why worry about XML anyway? 59 | 60 | Finally, while full featured, this class isn't as robust as it could be. There is almost no error catching. No try/catch blocks, no asserts. The only error checking done is to make sure that the file loads and saves. If it does not, the function gracefully fails, but no error is reported. This code is not heavily tested, there may be bugs. 61 | 62 | If you find a bug, or would like to submit enhancements to the code, please contact me. 63 | 64 | # Update - Sept 23, 2004 # 65 | I made a few changes to the code and this article. First, I made all the functions static. You no longer need to create an object from the CIniFile class first in order to call the functions. Also, I realized that Record.Commented was being declared as a string - however, it should only ever store either a "#" or a ";". So I made it a char, and then added an enum in order to set the comment character, like this: 66 | 67 | CIniFile::CommentRecord(CIniFile::CommentChar::Pound, "MyKey","YourSection",FileName) 68 | 69 | Finally, I repacked the zip file - instead of zipping up the entire VS project, I just included the source code files, and a (Windows only) executable of the demo project. This took the file size down to 68k, which should be easier for those with slower connection speeds to stomach. 70 | 71 | # License # 72 | This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL) 73 | 74 | # About the Author # 75 | [**Todd Davis**](http://www.codeproject.com/Members/Todd-Davis) 76 | Systems Engineer Virtual RadioLogic 77 | United States 78 | 79 | Todd Davis has been working in web and application development for several years, using Silverlight, ASP.NET, VB.NET, C#, C++ and Javascript, as well as a great deal of work with SQL server and IIS. 80 | 81 | He currently works for Virtual Radiologic in Eden Prairie, MN, however he is better known for his varied work in the open source community, especially the DotNetNuke project for which he provided several world-renowned training videos and modules. A huge advocate of open source and open knowledge sharing, everything on his website (www.SeaburyDesign.com) is always offered for free. 82 | 83 | Whenever he is not actively coding at his laptop (a rarity to be sure), he can be found woodworking, walking with his wife and kids, or motoring along the back roads of MN on his Harley Davidson Fatboy. -------------------------------------------------------------------------------- /Heartbeat/Heartbeat.cxx: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * 3 | * 文件名称:Heartbeat.cxx 4 | * 摘 要:跨Windows和Linux平台的Heartbeat类 5 | * 6 | * 当前版本:0.1 7 | * 作 者:Jaxon Jia 8 | * 创建日期:2013/07/24 9 | * 10 | * 修改历史: 11 | * | Date | Programmer | Description 12 | * | | | 13 | *********************************************************************/ 14 | 15 | #ifndef __Heartbeat__ 16 | #define __Heartbeat__ 17 | 18 | #include "Heartbeat.hh" 19 | 20 | Heartbeat::Heartbeat(void) 21 | { 22 | } 23 | 24 | Heartbeat::Heartbeat(HBRUNTYPE hb_type, 25 | const char* ip, 26 | u_int port/*=DEFAULT_PORT*/, 27 | u_int interval/*=INTERVAL_SLEEP*/, 28 | u_int tolerance/*=TOLERANCE*/) 29 | { 30 | init(hb_type, ip, port, interval, tolerance); 31 | } 32 | 33 | Heartbeat::~Heartbeat(void) 34 | { 35 | closesock(m_sock); 36 | } 37 | 38 | /********************************************************************* 39 | * 函数名称: init 40 | * 函数描述: 初始化 41 | * 参 数: 42 | * [IN]ip const char * IP地址 43 | * [IN]port u_int 端口 44 | * [IN]interval u_int 发送心跳包的间隔 45 | * [IN]tolerance u_int 心跳超时间隔时间 46 | * 返 回 值: N/A 47 | * 创 建: Jaxon Jia (sz082169) 48 | * 创建日期: 2013/07/24 49 | *********************************************************************/ 50 | void Heartbeat::init(HBRUNTYPE hb_type, const char* ip, u_int port, u_int interval, u_int tolerance) 51 | { 52 | m_hb_type = hb_type; 53 | strcpy(m_ip, ip); 54 | m_port = port; 55 | m_interval = interval; 56 | m_tolerance = tolerance; 57 | 58 | init_sock(); 59 | } 60 | 61 | /********************************************************************* 62 | * 函数名称: send_msg 63 | * 函数描述: 消息发送函数 64 | * 参 数: 65 | * [IN]type HBMSGTYPE 消息类型 66 | * [IN]content const char * 消息内容 67 | * [IN]len u_int 消息内容的长度 68 | * 返 回 值: 发送成功返回0,否则返回负值 69 | * 创 建: Jaxon Jia (sz082169) 70 | * 创建日期: 2013/07/24 71 | *********************************************************************/ 72 | int Heartbeat::send_msg(HBMSGTYPE type, const char* content, u_int len) 73 | { 74 | u_int pkt_len = sizeof(HBMSG) + len; 75 | HBMSG* msg = (HBMSG*)malloc(pkt_len); 76 | msg->type = type; 77 | msg->timestamp = cur_time(); 78 | msg->len = pkt_len; 79 | memcpy(msg->content, content, len); 80 | msg->content[len] = '\0'; 81 | 82 | struct sockaddr_in saddrsend = {0}; 83 | 84 | saddrsend.sin_family = AF_INET; 85 | saddrsend.sin_port = htons(m_port); 86 | saddrsend.sin_addr.s_addr = inet_addr(m_ip); 87 | 88 | int sendlen = sendto(m_sock, (char*)msg, pkt_len, 0, (struct sockaddr*)&saddrsend, sizeof(saddrsend)); 89 | free(msg); 90 | if (sendlen < 0) 91 | { 92 | TRACE("Heartbeat -- Socket send error! ERR:%d", errno); 93 | return HB_ERR_SOCK_SEND; 94 | } 95 | TRACE("Heartbeat -- Send %d byte.", sendlen); 96 | return HB_OK; 97 | } 98 | 99 | int Heartbeat::run() 100 | { 101 | return new_thread(threadfunc, this); 102 | } 103 | 104 | /********************************************************************* 105 | * 函数名称: as_client 106 | * 函数描述: 作为客户端运行时的心跳线程函数, as_client和as_server互斥 107 | * 参 数: N/A 108 | * 返 回 值: N/A 109 | * 创 建: Jaxon Jia (sz082169) 110 | * 创建日期: 2013/07/25 111 | *********************************************************************/ 112 | int Heartbeat::as_client() 113 | { 114 | TRACE("Heartbeat -- Send to IP:Port = %s:%d!", m_ip, m_port); 115 | while (true) 116 | {// 定时发送心跳 117 | send_msg(HB_MSG_RUNNING, "Heartbeat", strlen("Heartbeat")); 118 | TRACE("Heartbeat -- Send Heartbeat!"); 119 | //callback(); // 回调处理 120 | mysleep(m_interval); 121 | } 122 | 123 | return HB_OK; 124 | } 125 | 126 | /********************************************************************* 127 | * 函数名称: as_server 128 | * 函数描述: 作为服务端运行时的心跳线程函数, as_client和as_server互斥 129 | * 参 数: N/A 130 | * 返 回 值: N/A 131 | * 创 建: Jaxon Jia (sz082169) 132 | * 创建日期: 2013/07/25 133 | *********************************************************************/ 134 | int Heartbeat::as_server() 135 | { 136 | TRACE("Heartbeat -- Listening IP:Port = %s:%d!", m_ip, m_port); 137 | 138 | fd_set read_set; 139 | char recvbuf[HB_BUF_SIZE] = {0}; 140 | 141 | sockaddr_in src_sin = {0}; 142 | socklen_t src_len = sizeof(src_sin); 143 | 144 | while (true) 145 | { 146 | FD_ZERO(&read_set); 147 | FD_SET(m_sock, &read_set); 148 | struct timeval timeout; 149 | timeout.tv_sec = 3; 150 | timeout.tv_usec = 0; 151 | 152 | int ret = select(m_sock + 1, &read_set, NULL, NULL, &timeout); 153 | 154 | if (0 == ret) 155 | { 156 | TRACE("Heartbeat -- Recivie udp packet timeout."); 157 | } 158 | else if (ret < 0) 159 | { 160 | TRACE("Heartbeat -- Select socket failed! Error: %d.", errno); 161 | return -1; 162 | } 163 | else if (ret > 0 && FD_ISSET(m_sock, &read_set)) 164 | { 165 | memset(recvbuf, 0, sizeof(recvbuf)); 166 | int recvlen = recvfrom(m_sock, recvbuf, HB_BUF_SIZE, 0, (sockaddr*)&src_sin, &src_len); 167 | if (recvlen < 0) 168 | { 169 | TRACE("Heartbeat -- recv socket failed! Error: %s\n", strerror(errno)); 170 | } 171 | else if (0 == recvlen) 172 | { 173 | continue; 174 | } 175 | else 176 | { 177 | callback((HBMSG*)recvbuf, &src_sin); // 回调处理 178 | } 179 | }//end of else if (ret > 0 && FD_ISSET(m_sock, &read_set)) 180 | } 181 | 182 | return HB_OK; 183 | } 184 | 185 | /********************************************************************* 186 | * 函数名称: callback 187 | * 函数描述: 线程回调函数 188 | * 参 数: 189 | * [IN]msg HBMSG * 发送或接收到的消息 190 | * [IN]src_sin sockaddr_in 发送或接收的IP,Port信息 191 | * 返 回 值: N/A 192 | * 创 建: Jaxon Jia (sz082169) 193 | * 创建日期: 2013/07/25 194 | *********************************************************************/ 195 | void* Heartbeat::callback(HBMSG* msg, sockaddr_in *src_sin) 196 | { 197 | if (m_hb_type == HB_CLIENT) 198 | { 199 | } 200 | else 201 | { 202 | char *ip = inet_ntoa(src_sin->sin_addr); 203 | u_int port = src_sin->sin_port; 204 | int len = msg->len - sizeof(HBMSG); 205 | char descript[HB_NODE_DESCRIPT] = {0}; 206 | memcpy(descript, msg->content, MIN(HB_NODE_DESCRIPT, len)); 207 | int n = node_list.size(); 208 | switch (msg->type) 209 | { 210 | case HB_MSG_REG: 211 | TRACE("Heartbeat -- Recv node register message!"); 212 | TRACE("Heartbeat -- IP:PORT = %s:%d, descript: %s", ip, port, descript); 213 | if (node_list.size() < HB_MAX_NODE_COUNT) 214 | { 215 | NODE node; 216 | strcpy(node.ip, ip); 217 | node.port = port; 218 | node.timestamp = msg->timestamp; 219 | node.islive = 1; 220 | node.descript = descript; 221 | node_list.push_back(node); 222 | } 223 | else 224 | { 225 | TRACE("Heartbeat -- node list size greater than HB_MAX_NODE_COUNT!"); 226 | } 227 | break; 228 | case HB_MSG_RUNNING: 229 | TRACE("Heartbeat -- Recv Heartbeat message!"); 230 | for (int i = 0; i < n; i++) 231 | { 232 | if (node_list[i].ip == ip && node_list[i].port == port) 233 | { 234 | if (msg->timestamp - node_list[i].timestamp > m_tolerance) 235 | { 236 | TRACE("Heartbeat -- Node %s:%u is dead! recv timestamp: %ll, last timestamp: %ll", 237 | ip, port, msg->timestamp, node_list[i].timestamp); 238 | node_list[i].islive = 0; 239 | } 240 | 241 | node_list[i].timestamp = msg->timestamp; 242 | break; 243 | } 244 | } 245 | break; 246 | case HB_MSG_QUIT: 247 | TRACE("Heartbeat -- Recv node exit message!"); 248 | for (int i = 0; i < n; i++) 249 | { 250 | if (node_list[i].ip == ip && node_list[i].port == port) 251 | { 252 | node_list[i].islive = 0; 253 | break; 254 | } 255 | } 256 | break; 257 | } 258 | } 259 | 260 | return (void*)HB_OK; 261 | } 262 | 263 | // 线程函数 264 | #ifdef WIN32 265 | void Heartbeat::threadfunc(void *param) 266 | #else 267 | void* Heartbeat::threadfunc(void *param) 268 | #endif 269 | { 270 | Heartbeat* hb = (Heartbeat*)param; 271 | 272 | if (hb->m_hb_type == HB_CLIENT) 273 | { 274 | hb->as_client(); 275 | } 276 | else 277 | { 278 | hb->as_server(); 279 | } 280 | } 281 | 282 | // 获取当前时间,精确到秒 283 | time_t Heartbeat::cur_time() 284 | { 285 | return time(NULL); 286 | } 287 | 288 | // socket初始化 289 | int Heartbeat::init_sock() 290 | { 291 | #ifdef WIN32 292 | WSADATA wsad; 293 | if (WSAStartup(MAKEWORD(2,2),&wsad) != 0) 294 | { 295 | TRACE("Heartbeat -- Socket init error!"); 296 | return HB_ERR_SOCK_INIT; 297 | } 298 | #endif 299 | 300 | struct sockaddr_in local_sock; 301 | 302 | if ((m_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) 303 | { 304 | TRACE("Heartbeat -- Socket init error!"); 305 | return HB_ERR_SOCK_INIT; 306 | } 307 | 308 | if (inet_pton(AF_INET|AF_INET6, m_ip, &local_sock.sin_addr) < 0) 309 | { 310 | TRACE("Heartbeat -- Invalid ip address!"); 311 | return HB_ERR_INVALID_PARAM; 312 | } 313 | 314 | memset(&local_sock, 0, sizeof(local_sock)); 315 | local_sock.sin_family = AF_INET; 316 | 317 | if (m_hb_type == HB_CLIENT) 318 | { 319 | local_sock.sin_port = INADDR_ANY; 320 | local_sock.sin_addr.s_addr = INADDR_ANY; 321 | } 322 | else 323 | { 324 | local_sock.sin_port = htons(m_port); 325 | local_sock.sin_addr.s_addr = inet_addr(m_ip); 326 | } 327 | 328 | int reuse = 1; 329 | int res = setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(int)); 330 | if (res < 0) 331 | { 332 | TRACE("Heartbeat -- Error to set reuse socket."); 333 | return HB_ERR_SOCK_SETOPT; 334 | } 335 | 336 | res = bind(m_sock, (sockaddr*)(&local_sock), sizeof(local_sock)); 337 | if (res < 0) 338 | { 339 | TRACE("Heartbeat -- Error to bind socket."); 340 | return HB_ERR_SOCK_BIND; 341 | } 342 | 343 | int bufszie = HB_BUF_SIZE; 344 | int sock_opt = (m_hb_type == HB_CLIENT) ? SO_SNDBUF : SO_RCVBUF; 345 | res = setsockopt(m_sock, SOL_SOCKET, sock_opt, (char*)&bufszie, sizeof(int)); 346 | if (res < 0) 347 | { 348 | TRACE("Heartbeat -- Error to set socket buffer size."); 349 | return HB_ERR_SOCK_SETOPT; 350 | } 351 | 352 | if (ntohl(inet_addr(m_ip)) > 0xe0000000 && ntohl(inet_addr(m_ip)) < 0xefffffff) 353 | {// multicast address 354 | struct ip_mreq mreq = {0}; 355 | mreq.imr_multiaddr.s_addr = inet_addr(m_ip); 356 | mreq.imr_interface.s_addr = INADDR_ANY; 357 | 358 | res = setsockopt(m_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq)); 359 | if(res < 0 ) 360 | { 361 | TRACE("Heartbeat -- Error to add membership."); 362 | return HB_ERR_SOCK_SETOPT; 363 | } 364 | } 365 | 366 | return HB_OK; 367 | } 368 | 369 | //============= 下面是跨平台相关函数 ================ 370 | 371 | // 延时函数 372 | void Heartbeat::mysleep(u_int ms) 373 | { 374 | #ifdef WIN32 375 | Sleep(ms); 376 | #else 377 | usleep(ms*1000); 378 | #endif 379 | } 380 | 381 | // 关闭socket 382 | int Heartbeat::closesock(int sock) 383 | { 384 | #ifdef WIN32 385 | return closesocket(sock); 386 | #else 387 | return close(sock); 388 | #endif 389 | } 390 | 391 | // 创建线程 392 | #ifdef WIN32 393 | int Heartbeat::new_thread(void (*func)(void*), void *param) 394 | { 395 | int ret = _beginthread(func, NULL, param); 396 | #else 397 | int Heartbeat::new_thread(void* (*func)(void*), void *param) 398 | { 399 | pthread_t handle = 0; 400 | int ret = pthread_create(&handle, (pthread_attr_t*)0, func, param); 401 | #endif 402 | if (ret >= 0) 403 | { 404 | TRACE("Heartbeat -- Begin thread success!"); 405 | } 406 | else 407 | { 408 | TRACE("Heartbeat -- ERROR: Begin thread fail! ERR:%d", ret); 409 | } 410 | return ret; 411 | } 412 | 413 | //=================================================== 414 | 415 | #endif // __Heartbeat__ 416 | 417 | -------------------------------------------------------------------------------- /CIniFile/Test/TestIniFile.cpp: -------------------------------------------------------------------------------- 1 | // TestCIniFile::cpp : Defines the entry point for the console application. 2 | // 3 | #include "stdafx.h" 4 | #include 5 | #include 6 | using namespace std; 7 | #include "IniFile.h" 8 | 9 | void Show(string FileName) 10 | { 11 | cout << endl 12 | << "++++++++++++++++++++++++++++++++++++++++" 13 | << endl 14 | << "+ Contents of the file are below +" 15 | << endl 16 | << "++++++++++++++++++++++++++++++++++++++++" 17 | << endl 18 | << CIniFile::Content(FileName) 19 | << endl 20 | << "++++++++++++++++++++++++++++++++++++++++" 21 | << endl << endl; 22 | system ("PAUSE"); 23 | system("cls"); 24 | } 25 | 26 | int _tmain(int argc, _TCHAR* argv[]) 27 | { 28 | //CIniFile IniFile; 29 | string FileName = "test.ini"; 30 | 31 | // Create a new file 32 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 33 | cout << "Attempting to create a new file called \"test.ini\"" << endl << endl; 34 | cout << "string FileName = \"test.ini\";" << endl; 35 | cout << "CIniFile::Create(FileName);" << endl << endl; 36 | if (CIniFile::Create(FileName)) cout << "File was successfully created" << endl << endl; 37 | else cout << "Failed to create the file" << endl << endl; 38 | Show(FileName); 39 | 40 | // Create a new section 41 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 42 | cout << "Attempting to create a new section called [MySection]" << endl << endl; 43 | cout << "CIniFile::AddSection(\"MySection\", FileName);" << endl << endl; 44 | if (CIniFile::AddSection("MySection",FileName)) cout << "Section was successfully created" << endl << endl; 45 | else cout << "Failed to create the section" << endl << endl; 46 | Show(FileName); 47 | 48 | // Add a key to the section 49 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 50 | cout << "Attempting to add a new key/value (MyKey=MyValue) to [MySection]" << endl << endl; 51 | cout << "CIniFile::SetValue(\"MyKey\",\"MyValue\",\"MySection\",FileName);" << endl << endl; 52 | if (CIniFile::SetValue("MyKey","MyValue","MySection",FileName)) cout << "Record was successfully created" << endl << endl; 53 | else cout << "Failed to create the record" << endl << endl; 54 | Show(FileName); 55 | 56 | // Add a key and create a section 57 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 58 | cout << "Attempting to add a new key/value (TestKey=TestValue)" << endl << "and create a new section [TestSection] at the same time" << endl << endl; 59 | cout << "CIniFile::SetValue(\"TestKey\",\"TestValue\",\"TestSection\",FileName);" << endl << endl; 60 | if (CIniFile::SetValue("TestKey","TestValue","TestSection",FileName)) cout << "Record and section were successfully created" << endl << endl; 61 | else cout << "Failed to create the record and section" << endl << endl; 62 | Show(FileName); 63 | 64 | // Change a key value 65 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 66 | cout << "Attempting to change the key/value for (MyKey=MyValue) to (MyKey=YourValue)" << endl << endl; 67 | cout << "CIniFile::SetValue(\"MyKey\",\"YourValue\",\"MySection\",FileName);" << endl << endl; 68 | if (CIniFile::SetValue("MyKey","YourValue","MySection",FileName)) cout << "Record was successfully changed" << endl << endl; 69 | else cout << "Failed to change the record" << endl << endl; 70 | Show(FileName); 71 | 72 | // Get a value 73 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 74 | cout << "Attempting to get the value of MyKey" << endl << endl; 75 | cout << "CIniFile::GetValue(\"MyKey\",\"MySection\",FileName);" << endl << endl; 76 | string v = CIniFile::GetValue("MyKey","MySection",FileName); 77 | cout << "The value of MyKey is: " << v.c_str() << endl << endl; 78 | Show(FileName); 79 | 80 | // Get a list of Sections 81 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 82 | cout << "Attempting to get a list of sections" << endl << endl; 83 | cout << "CIniFile::GetSectionNames(FileName);" << endl << endl; 84 | vector s = CIniFile::GetSectionNames(FileName); 85 | cout << "The sections are returned as a std::vector\n\n"; 86 | for(int i=0; i < (int)s.size(); i++) 87 | cout << s[i].c_str() << endl; 88 | Show(FileName); 89 | 90 | // Section Exists 91 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 92 | cout << "Attempting to verify that [MySection] exists" << endl << endl; 93 | cout << "CIniFile::SectionExists(\"MySection\",FileName);" << endl << endl; 94 | if (CIniFile::SectionExists("MySection",FileName)) cout << "Section exists" << endl << endl; 95 | else cout << "Section does not exist" << endl << endl; 96 | Show(FileName); 97 | 98 | // Record Exists 99 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 100 | cout << "Attempting to verify that MyKey exists" << endl << endl; 101 | cout << "CIniFile::RecordExists(\"MyKey\",\"MySection\",FileName);" << endl << endl; 102 | if (CIniFile::RecordExists("MyKey","MySection",FileName)) cout << "Record exists" << endl << endl; 103 | else cout << "Record does not exist" << endl << endl; 104 | Show(FileName); 105 | 106 | // Case Sensitive 107 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 108 | cout << "BE CAREFUL - functions in CIniFile are CASE-SENSITIVE" << endl << endl; 109 | cout << "CIniFile::RecordExists(\"mykey\",\"MySection\",FileName);" << endl << endl; 110 | if (CIniFile::RecordExists("mykey","MySection",FileName)) cout << "Record exists" << endl << endl; 111 | else cout << "Record does not exist" << endl << endl; 112 | Show(FileName); 113 | 114 | // Add a comment to the section 115 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 116 | cout << "Attempting to add comments to [MySection]" << endl << endl; 117 | cout << "CIniFile::SetSectionComments(\"# This Section was created by CIniFile\",\"MySection\",FileName);" << endl << endl; 118 | if (CIniFile::SetSectionComments("# This Section was created by CIniFile","MySection",FileName)) cout << "Comments were successfully added" << endl << endl; 119 | else cout << "Failed to add the comments" << endl << endl; 120 | Show(FileName); 121 | 122 | // Add a comment to the record 123 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 124 | cout << "Attempting to add comments to MyKey" << endl << endl; 125 | cout << "CIniFile::SetRecordComments(\"# This Key was created by CIniFile\",\"MyKey\",\"MySection\",FileName);" << endl << endl; 126 | if (CIniFile::SetRecordComments("# This Key was created by CIniFile","MyKey","MySection",FileName)) cout << "Comments were successfully added" << endl << endl; 127 | else cout << "Failed to add the comments" << endl << endl; 128 | Show(FileName); 129 | 130 | // Rename Section 131 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 132 | cout << "Attempting to rename [MySection] to [YourSection]" << endl << endl; 133 | cout << "CIniFile::RenameSection(\"MySection\",\"YourSection\",FileName);" << endl << endl; 134 | if (CIniFile::RenameSection("MySection","YourSection",FileName)) cout << "Section was successfully changed" << endl << endl; 135 | else cout << "Failed to change the section" << endl << endl; 136 | Show(FileName); 137 | 138 | // Multiple comments 139 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 140 | cout << "Multiple comments can be added by putting \\n# in the comments string" << endl << endl; 141 | cout << "CIniFile::SetSectionComments(\"# This Section was created by CIniFile\\n# Kids, don't try this at home \\n\",\"YourSection\",FileName);" << endl << endl; 142 | if (CIniFile::SetSectionComments("# This Section was created by CIniFile\n# Kids, don't try this at home","YourSection",FileName)) cout << "Comments were successfully added" << endl << endl; 143 | else cout << "Failed to add the comments" << endl << endl; 144 | Show(FileName); 145 | 146 | // Remove comments 147 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 148 | cout << "Comments are removed by setting them to \"\"" << endl << endl; 149 | cout << "CIniFile::SetRecordComments(\"\",\"MyKey\",\"YourSection\",FileName);" << endl << endl; 150 | if (CIniFile::SetRecordComments("","MyKey","YourSection",FileName)) cout << "Comments were successfully removed" << endl << endl; 151 | else cout << "Failed to remove the comments" << endl << endl; 152 | Show(FileName); 153 | 154 | // Comment entire section 155 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 156 | cout << "Attempting to comment the entire section [YourSection]" << endl << endl; 157 | cout << "CIniFile::CommentSection(\"#\",\"YourSection\",FileName);" << endl << endl; 158 | if (CIniFile::CommentSection('#',"YourSection",FileName)) cout << "Section was successfully commented" << endl << endl; 159 | else cout << "Failed to comment the section" << endl << endl; 160 | Show(FileName); 161 | 162 | // UnComment entire section 163 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 164 | cout << "Attempting to un-comment the entire section [YourSection]" << endl << endl; 165 | cout << "CIniFile::UnCommentSection(\"YourSection\",FileName);" << endl << endl; 166 | if (CIniFile::UnCommentSection("YourSection",FileName)) cout << "Section was successfully un-commented" << endl << endl; 167 | else cout << "Failed to un-comment the section" << endl << endl; 168 | Show(FileName); 169 | 170 | // Comment a single record 171 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 172 | cout << "Attempting to comment the record MyKey" << endl << endl; 173 | cout << "(Note that both # and ; are recognized as commented lines by CIniFile)" << endl << endl; 174 | cout << "CIniFile::CommentRecord(CIniFile::CommentChar::Pound,\"MyKey\",\"YourSection\",FileName);" << endl << endl; 175 | if (CIniFile::CommentRecord(CIniFile::CommentChar::Pound,"MyKey","YourSection",FileName)) cout << "Record was successfully commented" << endl << endl; 176 | else cout << "Failed to comment the record" << endl << endl; 177 | Show(FileName); 178 | 179 | // UnComment a single record 180 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 181 | cout << "Attempting to un-comment the record MyKey" << endl << endl; 182 | cout << "CIniFile::UnCommentRecord(\"MyKey\",\"YourSection\",FileName);" << endl << endl; 183 | if (CIniFile::UnCommentRecord("MyKey","YourSection",FileName)) cout << "Record was successfully un-commented" << endl << endl; 184 | else cout << "Failed to un-comment the record" << endl << endl; 185 | Show(FileName); 186 | 187 | // Sort 188 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 189 | cout << "Attempting to sort the file - false means ASCENDING, true means DESCENDING" << endl << endl; 190 | cout << "(Note that the comments will stay with their targets)" << endl << endl; 191 | cout << "CIniFile::Sort(FileName,false);" << endl << endl; 192 | if (CIniFile::Sort(FileName,false)) cout << "File was successfully sorted" << endl << endl; 193 | else cout << "Failed to sort the file" << endl << endl; 194 | Show(FileName); 195 | 196 | // Delete entire section 197 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 198 | cout << "Attempting to delete the entire section [TestSection]" << endl << endl; 199 | cout << "CIniFile::DeleteSection(\"TestSection\",FileName);" << endl << endl; 200 | if (CIniFile::DeleteSection("TestSection",FileName)) cout << "Section was successfully deleted" << endl << endl; 201 | else cout << "Failed to delete the section" << endl << endl; 202 | Show(FileName); 203 | 204 | // Delete record 205 | cout << "TestIniFile - Demo program for the CIniFile Class" << endl << endl; 206 | cout << "Attempting to delete the record 23 | #include 24 | 25 | #include "optionparser.h" 26 | 27 | using option::Option; 28 | using option::Descriptor; 29 | using option::Parser; 30 | using option::Stats; 31 | using option::ArgStatus; 32 | 33 | struct Arg: public option::Arg 34 | { 35 | static ArgStatus Required(const Option& option, bool) 36 | { 37 | return option.arg == 0 ? option::ARG_ILLEGAL : option::ARG_OK; 38 | } 39 | static ArgStatus Empty(const Option& option, bool) 40 | { 41 | return (option.arg == 0 || option.arg[0] == 0) ? option::ARG_OK : option::ARG_IGNORE; 42 | } 43 | }; 44 | 45 | char* gettext(const char * msgid) 46 | { 47 | return (char*) msgid; 48 | } 49 | 50 | const Descriptor empty_usage[] = { { 0, 0, 0, 0, 0, 0 } }; 51 | 52 | const Descriptor minimal_usage[] = // 53 | { { 0, 0, "x", "", Arg::None, 0 }, // 54 | { 0, 0, 0, 0, 0, 0 } }; 55 | 56 | const Descriptor optional_usage[] = // 57 | { { 0, 0, "f", "", Arg::Required, 0 }, // 58 | { 0, 0, 0, 0, 0, 0 } }; 59 | 60 | const Descriptor gettext_usage[] = // 61 | { { 0, 0, "f", "", Arg::Required, gettext("This is a test") }, // 62 | { 0, 0, 0, 0, 0, 0 } }; 63 | 64 | enum OptionIndex 65 | { 66 | UNKNOWN, FOO, VERBOSE, X, ABBREVIATE, EMPTY 67 | }; 68 | enum OptionType 69 | { 70 | UNUSED = 0, DISABLED = 1, ENABLED = 2 71 | }; 72 | 73 | const Descriptor multi_usage[] = // 74 | { { UNKNOWN, 0, "", "", Arg::None, 0 }, // UNKNOWN option catch-all 75 | { FOO, ENABLED, "", "enable-foo", Arg::None, 0 }, // FOO enable 76 | { FOO, DISABLED, "", "disable-foo", Arg::None, 0 }, // FOO disable 77 | { VERBOSE, 0, "v", "verbose", Arg::None, 0 }, // VERBOSE (counted option) 78 | { X, 0, "X", "X", Arg::Required, 0 }, // -X, -X , -X=, --X= 79 | { ABBREVIATE, 0, "", "abbreviate-me", Arg::None, 0 }, // ABBREVIATE 80 | { EMPTY, 0, "", "emptyarg", Arg::Empty, 0 }, // EMPTY (ignores arguments that are not "") 81 | { 0, 0, 0, 0, 0, 0 } }; 82 | 83 | const char* empty_args[] = { 0 }; 84 | const char* non_options[] = { "1", "2", "3", (const char*) -1 }; 85 | const char* unknown_option[] = { "--unknown", "nonoption", 0 }; 86 | const char* lone_minus[] = { "-f", "-", "-", 0 }; 87 | const char* lone_doubleminus[] = { "--", 0 }; 88 | 89 | // NOTE: (const char*) -1 is used to cause a segfault should this element be dereferenced. 90 | // 0 is not used here, because the parser explicitly checks for 0 which could mask bugs. 91 | // If a number of arguments >= 0 is passed, the parser is supposed to honor that and never 92 | // dereference an element beyond the last. 93 | const char* multi1[] = 94 | { "--enable-foo", "--unknown1", "-u", "-vX", "xyzzy", "--", "--strangefilename", (const char*) -1 }; 95 | const char* multi2[] = { "-vvXfoo", "-X", "bar", "-X=foobar", "-X", "", "--disable-foo", "-v", (const char*) -1 }; 96 | const char* multi3[] = { "-abbr", "-abb", "--emptyarg", "-verbose", "--emptyarg", "", "--emptyarg=", "nonoption1", 97 | "nonoption2", (const char*) -1 }; 98 | 99 | const char* illegal[] = { "-X", 0 }; 100 | const char* reorder[] = { "-X", "--", "-", "-X", "--", "foo", "-v", "--", "bar", "--", 0 }; 101 | const char* reorder2[] = { "-X", "--", "-", "-X", "--", "-", 0 }; 102 | 103 | int count(const char** args) 104 | { 105 | for (int c = 0;; ++c) 106 | if (args[c] == (const char*) -1) 107 | return c; 108 | } 109 | 110 | bool eq(const char* s1, const char* s2) 111 | { 112 | if (s1 == s2) 113 | return true; 114 | 115 | if (s1 == 0 || s2 == 0) 116 | return false; 117 | 118 | while (*s1 != 0 && *s2 != 0) 119 | { 120 | ++s1; 121 | ++s2; 122 | } 123 | 124 | return *s1 == *s2; 125 | } 126 | 127 | int main() 128 | { 129 | { 130 | Stats stats(empty_usage, -1, empty_args); 131 | stats.add(empty_usage, 0, empty_args); 132 | assert(stats.buffer_max == 1); 133 | assert(stats.options_max == 1); 134 | Option buffer[stats.buffer_max]; 135 | Option options[stats.options_max]; 136 | Parser parse(empty_usage, 99, empty_args, options, buffer); 137 | parse.parse(empty_usage, -1, empty_args, options, buffer); 138 | assert(parse.optionsCount() == 0); 139 | assert(parse.nonOptionsCount() == 0); 140 | assert(!buffer[0]); 141 | assert(!options[0]); 142 | assert(buffer[0].count()==0); 143 | assert(parse.nonOptions()==0); 144 | 145 | stats.add(empty_usage, 3, non_options); 146 | assert(stats.buffer_max == 1); 147 | assert(stats.options_max == 1); 148 | parse.parse(empty_usage, 3, non_options, options, buffer); 149 | assert(parse.optionsCount() == 0); 150 | assert(parse.nonOptionsCount() == 3); 151 | assert(!buffer[0]); 152 | assert(!options[0]); 153 | assert(parse.nonOptions()==&non_options[0]); 154 | 155 | stats.add(minimal_usage, -1, unknown_option); 156 | assert(stats.buffer_max == 1); 157 | assert(stats.options_max == 2); 158 | parse.parse(minimal_usage, -1, unknown_option, options, buffer); 159 | assert(parse.optionsCount() == 0); 160 | assert(parse.nonOptionsCount() == 1); 161 | assert(!buffer[0]); 162 | assert(!options[0]); 163 | assert(parse.nonOptions()==&unknown_option[1]); 164 | } 165 | { 166 | Stats stats(gettext_usage, -1, lone_minus); 167 | Stats stats2; 168 | stats2.add(gettext_usage, -1, lone_minus); 169 | assert(stats.buffer_max == 2); 170 | assert(stats.options_max == 2); 171 | assert(stats2.buffer_max == 2); 172 | assert(stats2.options_max == 2); 173 | Option buffer[stats.buffer_max]; 174 | Option options[stats.options_max]; 175 | Parser parse; 176 | parse.parse(gettext_usage, -1, lone_minus, options, buffer); 177 | assert(parse.optionsCount() == 1); 178 | assert(parse.nonOptionsCount() == 1); 179 | assert(parse.nonOptions()==&lone_minus[2]); 180 | assert(options[0]); 181 | assert(buffer[0]); 182 | assert(options[0].count()==1); 183 | assert(options[0].isFirst()); 184 | assert(options[0].isLast()); 185 | assert(options[0].first() == options[0]); 186 | assert(options[0].last() == options[0]); 187 | assert(options[0].prevwrap() == &options[0]); 188 | assert(options[0].nextwrap() == &options[0]); 189 | assert(options[0].prev() == 0); 190 | assert(options[0].next() == 0); 191 | assert(options[0].desc == &gettext_usage[0]); 192 | assert(eq(options[0].name, "f")); 193 | assert(eq(options[0].arg, "-")); 194 | } 195 | { 196 | Stats stats(optional_usage, -1, lone_minus); 197 | Stats stats2; 198 | stats2.add(optional_usage, -1, lone_minus); 199 | assert(stats.buffer_max == 2); 200 | assert(stats.options_max == 2); 201 | assert(stats2.buffer_max == 2); 202 | assert(stats2.options_max == 2); 203 | Option buffer[stats.buffer_max]; 204 | Option options[stats.options_max]; 205 | Parser parse; 206 | parse.parse(optional_usage, -1, lone_minus, options, buffer); 207 | assert(parse.optionsCount() == 1); 208 | assert(parse.nonOptionsCount() == 1); 209 | assert(parse.nonOptions()==&lone_minus[2]); 210 | assert(options[0]); 211 | assert(buffer[0]); 212 | assert(options[0].count()==1); 213 | assert(options[0].isFirst()); 214 | assert(options[0].isLast()); 215 | assert(options[0].first() == options[0]); 216 | assert(options[0].last() == options[0]); 217 | assert(options[0].prevwrap() == &options[0]); 218 | assert(options[0].nextwrap() == &options[0]); 219 | assert(options[0].prev() == 0); 220 | assert(options[0].next() == 0); 221 | assert(options[0].desc == &optional_usage[0]); 222 | assert(eq(options[0].name, "f")); 223 | assert(eq(options[0].arg, "-")); 224 | } 225 | { 226 | Stats stats; 227 | stats.add(minimal_usage, -1, lone_doubleminus); 228 | assert(stats.buffer_max == 1); 229 | assert(stats.options_max == 2); 230 | Option buffer[stats.buffer_max]; 231 | Option options[stats.options_max]; 232 | Parser parse(minimal_usage, -1, lone_doubleminus, options, buffer); 233 | assert(parse.optionsCount() == 0); 234 | assert(parse.nonOptionsCount() == 0); 235 | assert(!buffer[0]); 236 | assert(!options[0]); 237 | assert(parse.nonOptions()==0); 238 | } 239 | { 240 | Stats stats; 241 | stats.add(multi_usage, count(multi1), multi1, 4, true); 242 | assert(stats.buffer_max == 6); 243 | assert(stats.options_max == 7); 244 | stats.add(multi_usage, count(multi2), multi2, 4, true); 245 | assert(stats.buffer_max == 14); 246 | assert(stats.options_max == 7); 247 | stats.add(multi_usage, count(multi3), multi3, 4, true); 248 | assert(stats.buffer_max == 22); 249 | assert(stats.options_max == 7); 250 | Option buffer[stats.buffer_max]; 251 | Option options[stats.options_max]; 252 | assert(options[FOO].last()->type() == UNUSED); 253 | assert(options[ABBREVIATE].count()==0); 254 | Parser parse; 255 | assert(!parse.error()); 256 | 257 | parse.parse(multi_usage, count(multi1), multi1, options, buffer, 4, true); 258 | assert(!parse.error()); 259 | assert(parse.optionsCount() == 5); 260 | assert(parse.nonOptionsCount() == 1); 261 | assert(eq(parse.nonOptions()[0],"--strangefilename")); 262 | assert(options[FOO].last()->type() == ENABLED); 263 | assert(eq(options[FOO].last()->name, "--enable-foo")); 264 | assert(options[FOO].last()->arg == 0); 265 | assert(options[UNKNOWN].count() == 2); 266 | assert(eq(options[UNKNOWN].first()->name,"--unknown1")); 267 | assert(eq(options[UNKNOWN].last()->name,"u")); 268 | assert(options[UNKNOWN].first()->arg == 0); 269 | assert(options[UNKNOWN].last()->arg == 0); 270 | assert(options[VERBOSE].count()==1); 271 | assert(options[VERBOSE].arg==0); 272 | assert(options[VERBOSE].name[0] == 'v' && options[VERBOSE].namelen == 1); 273 | assert(eq(options[X].arg,"xyzzy")); 274 | assert(eq(options[X].name,"X")); 275 | 276 | parse.parse(multi_usage, count(multi2), multi2, options, buffer, 4, true); 277 | assert(!parse.error()); 278 | assert(parse.optionsCount() == 13); 279 | assert(parse.nonOptionsCount() == 1); 280 | assert(eq(parse.nonOptions()[0],"--strangefilename")); 281 | assert(options[FOO].last()->type() == DISABLED); 282 | assert(options[FOO].last()->arg == 0); 283 | assert(options[UNKNOWN].count() == 2); 284 | assert(eq(options[UNKNOWN].first()->name,"--unknown1")); 285 | assert(eq(options[UNKNOWN].last()->name,"u")); 286 | assert(options[VERBOSE].count()==4); 287 | assert(options[X].count()==5); 288 | const char* Xargs[] = { "xyzzy", "foo", "bar", "foobar", "", "sentinel" }; 289 | const char** Xarg = &Xargs[0]; 290 | for (Option* Xiter = options[X]; Xiter != 0; Xiter = Xiter->next()) 291 | assert(eq(Xiter->arg, *Xarg++)); 292 | 293 | assert(!options[ABBREVIATE]); 294 | parse.parse(multi_usage, count(multi3), multi3, options, buffer, 4, true); 295 | assert(!parse.error()); 296 | assert(parse.optionsCount() == 21); 297 | assert(parse.nonOptionsCount() == 2); 298 | assert(eq(parse.nonOptions()[0],"nonoption1")); 299 | assert(eq(parse.nonOptions()[1],"nonoption2")); 300 | assert(options[ABBREVIATE]); 301 | assert(options[EMPTY].count()==3); 302 | assert(options[EMPTY].first()->arg==0); 303 | assert(eq(options[EMPTY].last()->arg,"")); 304 | assert(eq(options[EMPTY].last()->prev()->arg,"")); 305 | assert(options[FOO].last()->type() == DISABLED); 306 | assert(options[UNKNOWN].count() == 5); 307 | assert(eq(options[UNKNOWN].first()->name,"--unknown1")); 308 | assert(options[UNKNOWN].first()->arg == 0); 309 | assert(eq(options[UNKNOWN].last()->name,"b")); 310 | assert(options[VERBOSE].count()==5); 311 | assert(options[X].count()==5); 312 | Xarg = &Xargs[0]; 313 | for (Option* Xiter = options[X]; Xiter != 0; Xiter = Xiter->next()) 314 | assert(eq(Xiter->arg, *Xarg++)); 315 | 316 | for (Option* opt = buffer[0]; *opt; ++opt) 317 | if (opt->desc->check_arg != Arg::Required && opt->desc->check_arg != Arg::Empty) 318 | assert(opt->arg == 0); 319 | } 320 | { 321 | Option buffer[2]; 322 | Option options[20]; 323 | Parser parse; 324 | assert(!parse.error()); 325 | parse.parse(multi_usage, -1, illegal, options, buffer, 0, false, 2); 326 | assert(parse.error()); 327 | } 328 | { 329 | Stats stats(multi_usage, count(multi3), multi3, 0, true); 330 | const int bufmax = 3; 331 | Option buffer[bufmax]; 332 | Option options[stats.options_max]; 333 | assert(!options[ABBREVIATE]); 334 | Parser parse(multi_usage, count(multi3), multi3, options, buffer, 4, true, bufmax); 335 | assert(!parse.error()); 336 | assert(parse.optionsCount() == bufmax); 337 | assert(parse.nonOptionsCount() == 2); 338 | assert(eq(parse.nonOptions()[0],"nonoption1")); 339 | assert(eq(parse.nonOptions()[1],"nonoption2")); 340 | assert(options[ABBREVIATE]); 341 | assert(options[UNKNOWN].count() == 2); // because of buxmax the 2nd 'b' cannot be stored 342 | assert(options[UNKNOWN].first()->name[0] == 'a' && options[UNKNOWN].first()->namelen == 1); 343 | assert(options[UNKNOWN].first()->arg == 0); 344 | assert(eq(options[UNKNOWN].last()->name,"bb")); 345 | } 346 | { 347 | Stats stats(true, multi_usage, -1, reorder); 348 | Option buffer[stats.buffer_max]; 349 | Option options[stats.options_max]; 350 | Parser parse(true, multi_usage, -1, reorder, options, buffer); 351 | assert(!parse.error()); 352 | assert(parse.optionsCount() == 3); 353 | assert(parse.nonOptionsCount() == 4); 354 | assert(parse.nonOptions() == &reorder[6]); 355 | } 356 | { 357 | Option buffer[10]; 358 | Option options[10]; 359 | Parser parse(true, multi_usage, 666, reorder2, options, buffer, 0, false, 10); 360 | assert(!parse.error()); 361 | assert(parse.optionsCount() == 2); 362 | assert(parse.nonOptionsCount() == 2); 363 | } 364 | 365 | fprintf(stdout, "All tests passed.\n"); 366 | return 0; 367 | } 368 | 369 | -------------------------------------------------------------------------------- /CIniFile/IniFile.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | #include ".\inifile.h" 3 | 4 | CIniFile::CIniFile(void) // Default constructor 5 | { 6 | } 7 | 8 | CIniFile::~CIniFile(void) 9 | { 10 | } 11 | 12 | // replace all old_value with new_value in 'str' 13 | string& replace_all(string& str, const string& old_value, const string& new_value) 14 | { 15 | while (true) 16 | { 17 | string::size_type pos(0); 18 | if((pos = str.find(old_value)) != string::npos) 19 | str.replace(pos,old_value.length(),new_value); 20 | else 21 | break; 22 | } 23 | return str; 24 | } 25 | 26 | // A function to trim whitespace from both sides of a given string 27 | void Trim(std::string& str, const std::string & ChrsToTrim = " \t\n\r", int TrimDir = 0) 28 | { 29 | size_t startIndex = str.find_first_not_of(ChrsToTrim); 30 | if (startIndex == std::string::npos){str.erase(); return;} 31 | if (TrimDir < 2) str = str.substr(startIndex, str.size()-startIndex); 32 | if (TrimDir!=1) str = str.substr(0, str.find_last_not_of(ChrsToTrim) + 1); 33 | // Trim whitespace from both sides of '=' 34 | if (str.at(0) != '#') str = replace_all(str, " ", ""); 35 | if (str.at(0) != '#') str = replace_all(str, "\t", ""); 36 | } 37 | 38 | //inline void TrimRight(std::string& str, const std::string & ChrsToTrim = " \t\n\r") 39 | //{ 40 | // Trim(str, ChrsToTrim, 2); 41 | //} 42 | 43 | //inline void TrimLeft(std::string& str, const std::string & ChrsToTrim = " \t\n\r") 44 | //{ 45 | // Trim(str, ChrsToTrim, 1); 46 | //} 47 | 48 | // A function to transform a string to uppercase if neccessary 49 | //void UCase(string& str, bool ucase) 50 | //{ 51 | // if(ucase) transform(str.begin(), str.end(), str.begin(), toupper); 52 | //} 53 | 54 | bool CIniFile::Load(string FileName, vector& content) 55 | { 56 | string s; // Holds the current line from the ini file 57 | string CurrentSection; // Holds the current section name 58 | 59 | ifstream inFile (FileName.c_str()); // Create an input filestream 60 | if (!inFile.is_open()) return false; // If the input file doesn't open, then return 61 | content.clear(); // Clear the content vector 62 | 63 | string comments = ""; // A string to store comments in 64 | 65 | while(!std::getline(inFile, s).eof()) // Read until the end of the file 66 | { 67 | Trim(s); // Trim whitespace from the ends 68 | if(!s.empty()) // Make sure its not a blank line 69 | { 70 | Record r; // Define a new record 71 | 72 | if((s[0]=='#')||(s[0]==';')) // Is this a commented line? 73 | { 74 | if ((s.find('[')==string::npos)&& // If there is no [ or = 75 | (s.find('=')==string::npos)) // Then it's a comment 76 | { 77 | comments += s + '\n'; // Add the comment to the current comments string 78 | } else { 79 | r.Commented = s[0]; // Save the comment character 80 | s.erase(s.begin()); // Remove the comment for further processing 81 | Trim(s); 82 | }// Remove any more whitespace 83 | } else r.Commented = ' '; // else mark it as not being a comment 84 | 85 | if(s.find('[')!=string::npos) // Is this line a section? 86 | { 87 | s.erase(s.begin()); // Erase the leading bracket 88 | s.erase(s.find(']')); // Erase the trailing bracket 89 | r.Comments = comments; // Add the comments string (if any) 90 | comments = ""; // Clear the comments for re-use 91 | r.Section = s; // Set the Section value 92 | r.Key = ""; // Set the Key value 93 | r.Value = ""; // Set the Value value 94 | CurrentSection = s; 95 | } 96 | 97 | if(s.find('=')!=string::npos) // Is this line a Key/Value? 98 | { 99 | r.Comments = comments; // Add the comments string (if any) 100 | comments = ""; // Clear the comments for re-use 101 | r.Section = CurrentSection; // Set the section to the current Section 102 | r.Key = s.substr(0,s.find('=')); // Set the Key value to everything before the = sign 103 | r.Value = s.substr(s.find('=')+1); // Set the Value to everything after the = sign 104 | } 105 | if(comments == "") // Don't add a record yet if its a comment line 106 | content.push_back(r); // Add the record to content 107 | } 108 | } 109 | 110 | inFile.close(); // Close the file 111 | return true; 112 | } 113 | 114 | bool CIniFile::Save(string FileName, vector& content) 115 | { 116 | ofstream outFile (FileName.c_str()); // Create an output filestream 117 | if (!outFile.is_open()) return false; // If the output file doesn't open, then return 118 | 119 | for (int i=0;i<(int)content.size();i++) // Loop through each vector 120 | { 121 | outFile << content[i].Comments; // Write out the comments 122 | if (content[i].Commented != ' ') 123 | outFile << content[i].Commented; 124 | 125 | if(content[i].Key == "") // Is this a section? 126 | outFile<< "[" << content[i].Section << "]" << endl; // Then format the section 127 | else 128 | outFile << content[i].Key << "=" << content[i].Value << endl; // Else format a key/value 129 | } 130 | 131 | outFile.close(); // Close the file 132 | return true; 133 | } 134 | 135 | string CIniFile::Content(string FileName) 136 | { 137 | string s=""; // Hold our return string 138 | vector content; // Holds the current record // Holds the current record 139 | 140 | if (Load(FileName, content)) // Make sure the file loads 141 | { 142 | for (int i=0;i<(int)content.size();i++) // Loop through the content 143 | { 144 | if(content[i].Comments != "") s += content[i].Comments; // Add the comments 145 | if(content[i].Commented != ' ') s += content[i].Commented; // If this is commented, then add it 146 | if((content[i].Key == "")) // Is this a section? 147 | s += '[' + content[i].Section + ']'; // Add the section 148 | else s += content[i].Key + '=' + content[i].Value; // Or the Key value to the return srting 149 | 150 | if (i != content.size()) s += '\n'; // If this is not the last line, add a CrLf 151 | } 152 | return s; // Return the contents 153 | } 154 | 155 | return ""; 156 | } 157 | 158 | vector CIniFile::GetSectionNames(string FileName) 159 | { 160 | vector data; // Holds the return data 161 | vector content; // Holds the current record // Holds the current record 162 | 163 | if (Load(FileName, content)) // Make sure the file is loaded 164 | { 165 | for (int i=0;i<(int)content.size();i++) // Loop through the content 166 | { 167 | if(content[i].Key =="") // If there is no key value, then its a section 168 | data.push_back(content[i].Section); // Add the section to the return data 169 | } 170 | } 171 | 172 | return data; // Return the data 173 | } 174 | 175 | vector CIniFile::GetSection(string SectionName, string FileName) 176 | { 177 | vector data; // Holds the return data 178 | vector content; // Holds the current record // Holds the current record 179 | 180 | if (Load(FileName, content)) // Make sure the file is loaded 181 | { 182 | for (int i=0;i<(int)content.size();i++) // Loop through the content 183 | { 184 | if((content[i].Section == SectionName) && // If this is the section name we want 185 | (content[i].Key != "")) // but not the section name itself 186 | data.push_back(content[i]); // Add the record to the return data 187 | } 188 | } 189 | 190 | return data; // Return the data 191 | } 192 | 193 | bool CIniFile::RecordExists(string KeyName, string SectionName, string FileName) 194 | { 195 | vector content; // Holds the current record // Holds the current record 196 | 197 | if (Load(FileName, content)) // Make sure the file is loaded 198 | { 199 | vector::iterator iter = std::find_if(content.begin(), 200 | content.end(), 201 | CIniFile::RecordSectionKeyIs(SectionName,KeyName)); // Locate the Section/Key 202 | 203 | if (iter == content.end()) return false; // The Section/Key was not found 204 | } 205 | return true; // The Section/Key was found 206 | } 207 | 208 | bool CIniFile::SectionExists(string SectionName, string FileName) 209 | { 210 | vector content; // Holds the current record // Holds the current record 211 | 212 | if (Load(FileName, content)) // Make sure the file is loaded 213 | { 214 | vector::iterator iter = std::find_if(content.begin(), 215 | content.end(), 216 | CIniFile::RecordSectionIs(SectionName)); // Locate the Section 217 | 218 | if (iter == content.end()) return false; // The Section was not found 219 | } 220 | return true; // The Section was found 221 | } 222 | 223 | vector CIniFile::GetRecord(string KeyName, string SectionName, string FileName) 224 | { 225 | vector data; // Holds the return data 226 | vector content; // Holds the current record // Holds the current record 227 | 228 | if (Load(FileName, content)) // Make sure the file is loaded 229 | { 230 | vector::iterator iter = std::find_if(content.begin(), 231 | content.end(), 232 | CIniFile::RecordSectionKeyIs(SectionName,KeyName)); // Locate the Record 233 | 234 | if (iter == content.end()) return data; // The Record was not found 235 | 236 | data.push_back (*iter); // The Record was found 237 | } 238 | return data; // Return the Record 239 | } 240 | 241 | string CIniFile::GetValue(string KeyName, string SectionName, string FileName) 242 | { 243 | vector content = GetRecord(KeyName,SectionName, FileName); // Get the Record 244 | 245 | if(!content.empty()) // Make sure there is a value to return 246 | return content[0].Value; // And return the value 247 | 248 | return ""; // No value was found 249 | } 250 | 251 | bool CIniFile::SetValue(string KeyName, string Value, string SectionName, string FileName) 252 | { 253 | vector content; // Holds the current record // Holds the current record 254 | 255 | if (Load(FileName, content)) // Make sure the file is loaded 256 | { 257 | if(!SectionExists(SectionName,FileName)) // If the Section doesn't exist 258 | { 259 | Record s = {"",' ',SectionName,"",""}; // Define a new section 260 | Record r = {"",' ',SectionName,KeyName,Value}; // Define a new record 261 | content.push_back(s); // Add the section 262 | content.push_back(r); // Add the record 263 | return Save(FileName,content); // Save 264 | } 265 | 266 | if(!RecordExists(KeyName,SectionName,FileName)) // If the Key doesn't exist 267 | { 268 | vector::iterator iter = std::find_if(content.begin(), 269 | content.end(), 270 | CIniFile::RecordSectionIs(SectionName)); // Locate the Section 271 | iter++; // Advance just past the section 272 | Record r = {"",' ',SectionName,KeyName,Value}; // Define a new record 273 | content.insert(iter,r); // Add the record 274 | return Save(FileName,content); // Save 275 | } 276 | 277 | vector::iterator iter = std::find_if(content.begin(), 278 | content.end(), 279 | CIniFile::RecordSectionKeyIs(SectionName,KeyName)); // Locate the Record 280 | 281 | iter->Value = Value; // Insert the correct value 282 | return Save(FileName,content); // Save 283 | } 284 | 285 | return false; // In the event the file does not load 286 | } 287 | 288 | bool CIniFile::RenameSection(string OldSectionName, string NewSectionName, string FileName) 289 | { 290 | vector content; // Holds the current record // Holds the current record 291 | 292 | if (Load(FileName, content)) // Make sure the file is loaded 293 | { 294 | for(vector::iterator iter = content.begin(); 295 | iter < content.end(); iter++) // Loop through the records 296 | { 297 | if(iter->Section == OldSectionName) // Is this the OldSectionName? 298 | iter->Section = NewSectionName; // Now its the NewSectionName 299 | } 300 | return Save(FileName,content); // Save 301 | } 302 | 303 | return false; // In the event the file does not load 304 | } 305 | 306 | bool CIniFile::CommentRecord(CommentChar cc, string KeyName,string SectionName,string FileName) 307 | { 308 | vector content; // Holds the current record // Holds the current record 309 | 310 | if (Load(FileName, content)) // Make sure the file is loaded 311 | { 312 | vector::iterator iter = std::find_if(content.begin(), 313 | content.end(), 314 | CIniFile::RecordSectionKeyIs(SectionName,KeyName)); // Locate the Section/Key 315 | 316 | if (iter == content.end()) return false; // The Section/Key was not found 317 | 318 | iter->Commented = cc; // Change the Comment value 319 | return Save(FileName,content); // Save 320 | 321 | } 322 | return false; // In the event the file does not load 323 | } 324 | 325 | bool CIniFile::UnCommentRecord(string KeyName,string SectionName,string FileName) 326 | { 327 | vector content; // Holds the current record // Holds the current record 328 | 329 | if (Load(FileName, content)) // Make sure the file is loaded 330 | { 331 | vector::iterator iter = std::find_if(content.begin(), 332 | content.end(), 333 | CIniFile::RecordSectionKeyIs(SectionName,KeyName)); // Locate the Section/Key 334 | 335 | if (iter == content.end()) return false; // The Section/Key was not found 336 | 337 | iter->Commented = ' '; // Remove the Comment value 338 | return Save(FileName,content); // Save 339 | 340 | } 341 | return false; // In the event the file does not load 342 | } 343 | 344 | bool CIniFile::CommentSection(char CommentChar, string SectionName, string FileName) 345 | { 346 | vector content; // Holds the current record // Holds the current record 347 | 348 | if (Load(FileName, content)) // Make sure the file is loaded 349 | { 350 | for(vector::iterator iter = content.begin(); iter < content.end(); iter++) 351 | { 352 | if(iter->Section == SectionName) // Is this the right section? 353 | iter->Commented = CommentChar; // Change the comment value 354 | } 355 | return Save(FileName,content); // Save 356 | } 357 | 358 | return false; // In the event the file does not load 359 | } 360 | 361 | bool CIniFile::UnCommentSection(string SectionName, string FileName) 362 | { 363 | vector content; // Holds the current record // Holds the current record 364 | 365 | if (Load(FileName, content)) // Make sure the file is loaded 366 | { 367 | for(vector::iterator iter = content.begin(); iter < content.end(); iter++) 368 | { 369 | if(iter->Section == SectionName) // Is this the right section? 370 | iter->Commented = ' '; // Remove the comment value 371 | } 372 | return Save(FileName,content); // Save 373 | } 374 | 375 | return false; // In the event the file does not load 376 | } 377 | 378 | bool CIniFile::DeleteRecord(string KeyName, string SectionName, string FileName) 379 | { 380 | vector content; // Holds the current record // Holds the current record 381 | 382 | if (Load(FileName, content)) // Make sure the file is loaded 383 | { 384 | vector::iterator iter = std::find_if(content.begin(), 385 | content.end(), 386 | CIniFile::RecordSectionKeyIs(SectionName,KeyName)); // Locate the Section/Key 387 | 388 | if (iter == content.end()) return false; // The Section/Key was not found 389 | 390 | content.erase(iter); // Remove the Record 391 | return Save(FileName,content); // Save 392 | 393 | } 394 | 395 | return false; // In the event the file does not load 396 | } 397 | 398 | bool CIniFile::DeleteSection(string SectionName, string FileName) 399 | { 400 | vector content; // Holds the current record // Holds the current record 401 | 402 | if (Load(FileName, content)) // Make sure the file is loaded 403 | { 404 | for(int i=(int)content.size()-1;i>-1;i--) // Iterate backwards through the content 405 | { 406 | if(content[i].Section == SectionName) // Is this related to the Section? 407 | content.erase (content.begin()+i); // Then erase it 408 | } 409 | 410 | return Save(FileName,content); // Save 411 | } 412 | return false; // In the event the file does not load 413 | } 414 | 415 | bool CIniFile::SetSectionComments(string Comments, string SectionName, string FileName) 416 | { 417 | vector content; // Holds the current record // Holds the current record 418 | 419 | if (Load(FileName, content)) // Make sure the file is loaded 420 | { 421 | for(vector::iterator iter = content.begin(); iter < content.end(); iter++) // Loop through the records 422 | { 423 | if((iter->Section == SectionName) && // Is this the Section? 424 | (iter->Key == "")) // And not a record 425 | { 426 | if (Comments.size() >= 2) // Is there a comment? 427 | { 428 | if (Comments.substr(Comments.size()-2) != "\n") // Does the string end in a newline? 429 | Comments += "\n"; // If not, add one 430 | } 431 | iter->Comments = Comments; // Set the comments 432 | 433 | return Save(FileName,content); // Save 434 | } 435 | } 436 | } 437 | return false; // In the event the file does not load 438 | } 439 | 440 | bool CIniFile::SetRecordComments(string Comments, string KeyName, string SectionName, string FileName) 441 | { 442 | vector content; // Holds the current record // Holds the current record 443 | 444 | if (Load(FileName, content)) // Make sure the file is loaded 445 | { 446 | vector::iterator iter = std::find_if(content.begin(), 447 | content.end(), 448 | CIniFile::RecordSectionKeyIs(SectionName,KeyName)); // Locate the Section/Key 449 | 450 | if (iter == content.end()) return false; // The Section/Key was not found 451 | 452 | if (Comments.size() >= 2) // Is there a comment? 453 | { 454 | if (Comments.substr(Comments.size()-2) != "\n") // Does the string end in a newline? 455 | Comments += "\n"; // If not, add one 456 | } 457 | iter->Comments = Comments; // Set the comments 458 | return Save(FileName,content); // Save 459 | 460 | } 461 | 462 | return false; // In the event the file does not load 463 | } 464 | 465 | vector CIniFile::GetSections(string FileName) 466 | { 467 | vector data; // Holds the return data 468 | vector content; // Holds the current record // Holds the current record 469 | 470 | if (Load(FileName, content)) // Make sure the file is loaded 471 | { 472 | for (int i=0;i<(int)content.size();i++) // Loop through the content 473 | { 474 | if(content[i].Key == "") // If this is a section 475 | data.push_back(content[i]); // Add the record to the return data 476 | } 477 | } 478 | 479 | return data; // Return the data 480 | } 481 | 482 | bool CIniFile::Sort(string FileName, bool Descending) 483 | { 484 | vector content; // Used to hold the sorted content 485 | vector sections = GetSections(FileName); // Get a list of Sections 486 | 487 | if(!sections.empty()) // Is there anything to process? 488 | { 489 | 490 | if(Descending) // Descending or Ascending? 491 | std::sort(sections.begin(), sections.end(), DescendingSectionSort()); 492 | else // Sort the Sections 493 | std::sort(sections.begin(), sections.end(), AscendingSectionSort()); 494 | 495 | for(vector::iterator iter = sections.begin(); iter < sections.end(); iter++) // For each Section 496 | { 497 | content.push_back(*iter); // Add the sorted Section to the content 498 | 499 | vector records = GetSection(iter->Section ,FileName); // Get a list of Records for this section 500 | 501 | if(Descending) // Descending or Ascending? 502 | std::sort(records.begin(), records.end(), DescendingRecordSort()); 503 | else // Sort the Records 504 | std::sort(records.begin(), records.end(), AscendingRecordSort()); 505 | 506 | for(vector::iterator it = records.begin(); it < records.end(); it++) // For each Record 507 | content.push_back(*it); // Add the sorted Record to the content 508 | } 509 | 510 | return Save(FileName,content); // Save 511 | } 512 | 513 | return false; // There were no sections 514 | } 515 | 516 | bool CIniFile::AddSection(string SectionName, string FileName) 517 | { 518 | vector content; // Holds the current record // Holds the current record 519 | 520 | if (Load(FileName, content)) // Make sure the file is loaded 521 | { 522 | Record s = {"",' ',SectionName,"",""}; // Define a new section 523 | content.push_back(s); // Add the section 524 | return Save(FileName,content); // Save 525 | } 526 | 527 | return false; // The file did not open 528 | } 529 | 530 | bool CIniFile::Create(string FileName) 531 | { 532 | vector content; // Create empty content 533 | return Save(FileName,content); // Save 534 | } 535 | 536 | --------------------------------------------------------------------------------