2016-05-12 16 views
1

我在寫一個C++程序,它有兩個可以完全獨立運行的函數。所以我想把它們分成兩個程序。如何將C++程序分解爲模塊

問題是,他們都依賴於相同的功能集(可以增長或改變)。我想要做的就是將這組函數作爲頭文件包含在這兩個程序中,所以我不必在每次改變內容時都複製/粘貼(我也討厭複製函數或任何東西)。

我知道是一個愚蠢的問題,但我找不到任何有關此事的文件。

如果代碼是必要的請求它,我會發布它。

謝謝!

編輯:

添加代碼:

均可獨立運行的功能是make_video()和delete_video() 請心目中,這還遠遠沒有完成。

#include <sys/types.h> 
#include <sys/stat.h> 
#include <iostream> 
#include <fstream> 
#include <sstream> 
#include <cstdlib> 
#include <fcntl.h> 
#include <errno.h> 
#include <unistd.h> 
#include <syslog.h> 
#include <string> 
#include <cstring> 
#include <dirent.h> 
#include <vector> 
#include <time.h> 
#include <csignal> 
#include <algorithm> 
#include <functional> 
#include <cctype> 
#include <locale> 

#include <mysql/mysql.h> 
#include <mysql_connection.h> 
#include <mysql_driver.h> 
#include <cppconn/driver.h> 
#include <cppconn/exception.h> 
#include <cppconn/resultset.h> 
#include <cppconn/statement.h> 

struct config_t{ 
    std::string sql_host; //mysql host 
    std::string sql_user; //mysql user 
    std::string sql_pass; //mysql password 
    std::string sql_db; //zoneminder database name 
    std::string sql_ev_zm; //zoneminder events table 
    std::string sql_ev_vid; //video events table 
    std::string sql_ev_videxp; //video events expiration table 
    std::string sql_mon; //zm monitors table 

    std::string dir_ev; //Zoneminder events directory 
    std::string dir_vid; //manager videos directory 
    std::string dir_ram; //Ramfs mount directory 
    std::string ram_size; //ramfs size 
}; 

int is_dir(const char *pathname){ 
    struct stat info; 

    if(stat(pathname, &info) != 0) 
     return -1; 
    else if(info.st_mode & S_IFDIR) // S_ISDIR() doesn't exist on my windows 
     return 1; 
    else 
     return 0; 


} 

// trim from start (in place) 
static inline void ltrim(std::string &s) { 
    s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace)))); 
} 

// trim from end (in place) 
static inline void rtrim(std::string &s) { 
    s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end()); 
} 

// trim from both ends (in place) 
static inline void trim(std::string &s) { 
    ltrim(s); 
    rtrim(s); 
} 

// trim from start (copying) 
static inline std::string ltrimmed(std::string s) { 
    ltrim(s); 
    return s; 
} 

// trim from end (copying) 
static inline std::string rtrimmed(std::string s) { 
    rtrim(s); 
    return s; 
} 

// trim from both ends (copying) 
static inline std::string trimmed(std::string s) { 
    trim(s); 
    return s; 
} 

bool DirectoryExists (const char* path){ 

    if(path == NULL)return false; 
    DIR *d; 
    d = opendir(path); 
    if (d){ 
     closedir(d); 
     return true; 
    } 
    return false; 
} 

std::ifstream::pos_type filesize(const char* filename){ 
    std::ifstream in(filename, std::ifstream::ate | std::ifstream::binary); 
    return in.tellg(); 
} 

bool mount_ramfs(config_t *conf){ 
    return false; 
} 


bool make_video(config_t *conf, std::string path = "", int depth = 0){ 
    try{ 
     sql::mysql::MySQL_Driver *driver; 
     sql::Connection *con; 
     sql::Statement *stmt; 
     sql::ResultSet *res; 

     driver = sql::mysql::get_mysql_driver_instance(); 
     con = driver->connect(conf->sql_host, conf->sql_user, conf->sql_pass); 
     stmt = con->createStatement(); 
     stmt->execute("USE " + conf->sql_db); 

     std::string query = "SELECT Id, MonitorId, StartTime, EndTime, Length, Frames FROM " + conf->sql_ev_zm + " WHERE EndTime IS NOT NULL LIMIT 10"; //select a bunch of events for processing, EndTime NOT NULL means that the event is complete and not corrupted 

     //syslog (LOG_DEBUG, "Mysql Query: %s", query.c_str()); 

     res = stmt->executeQuery(query); 


     // SELECT Id, MonitorId, StartTime FROM Events WHERE StartTime < NOW() - INTERVAL 1 DAY ORDER BY Id ASC LIMIT 1 
     // SELECT Id, MonitorId, StartTime FROM Events WHERE StartTime LIKE "%2015-11-18%" and MonitorId = 56 
     // conf.dir_ev + "/" + MonitorId + "/" + todir(StartTime) 

     while (res->next()) { 
      int id = res->getInt("Id"); 
      int monitor = res->getInt("MonitorId"); 
      std::string start_time = res->getString("StartTime"); 
      std::string end_time = res->getString("EndTime"); 
      int lenght = res->getInt("Length"); 
      int frames = res->getInt("Frames"); 

      //Get event directory form table data; the dir structure is id/YY/MM/DD/HH/mm/ss/ 

      char sttm[60] = {}; 
      std::strcpy(sttm, start_time.c_str()); 
      char * tkn = (char*)malloc(60); 
      std::stringstream pathSS; 

      pathSS << conf->dir_ev << '/' << id << '/'; //prepare the path 

      tkn = std::strtok (sttm," -:"); //here we tokenize the StartTime field to match the source directory structure 
      if (tkn != NULL) { 
       pathSS << tkn[2] << tkn[3] << '/'; 
       tkn = std::strtok (NULL, " -:"); 
      } 
      while (tkn != NULL) { 
       pathSS << tkn << '/'; 
       tkn = std::strtok (NULL, " -:"); 
      } 
      std::string src = pathSS.str(); 
      pathSS.clear(); 


      pathSS << conf->dir_vid << '/' << id << '/'; //prepare the path 
      std::string dest = pathSS.str(); 
      pathSS.clear(); 

      tkn = std::strtok (sttm," -:"); //here we tokenize the StartTime field to make the destinantion and filename 
      while (tkn != NULL) { 
       pathSS << tkn << '_'; //sadly this will always lead to "_.mp4" but its not that bad or important 
       tkn = std::strtok (NULL, " -:"); 
      } 
      pathSS << ".mp4"; 
      std::string fname = pathSS.str(); 
      pathSS.clear(); 

      //do event video and 
      /*std::string cmd = "mkdir -p " + conf->dir_vid + path; 
      syslog (LOG_DEBUG, "%s", cmd.c_str()); 
      std::system(cmd.c_str()); 
      cmd = "tar -zcf " + conf->dir_vid + path + "/" + dirlist[i] +".tar.gz " + conf->dir_ev + path + "/" + dirlist[i]; 
      syslog (LOG_DEBUG, "%s", cmd.c_str()); 
      std::system(cmd.c_str()); 
      cmd = "rm -rf " + conf->dir_ev + src + "*"; 
      syslog (LOG_DEBUG, "%s", cmd.c_str()); 
      std::system(cmd.c_str());*/ 
      try{ 
       //insert new row in videos table 
       pathSS << "INSERT INTO " << conf->sql_ev_vid << " (startTime, endTime, monitor, filename) VALUES (\'" << start_time << "\', \'" << end_time << "\', " << monitor << ",\'" << dest << fname << "\')"; 
       stmt->execute(pathSS.str()); 
       pathSS.clear(); 
       //delete non existing event 
       pathSS << "DELETE FROM " << conf->sql_ev_zm << " WHERE Id = " << id; 
       stmt->execute(pathSS.str()); 
       pathSS.clear(); 
      } 
      catch(sql::SQLException &e){ 
       syslog (LOG_ERR, "Mysql Exception: %s, ERRNO %i, MySQL State: %s", e.what(), e.getErrorCode(), std::string(e.getSQLState()).c_str()); 
       exit(EXIT_FAILURE); 
      } 

     } 
     delete res; 
     delete stmt; 
     delete con; 
    } 
    catch(sql::SQLException &e){ 
     syslog (LOG_ERR, "Mysql Exception: %s, ERRNO %i, MySQL State: %s", e.what(), e.getErrorCode(), std::string(e.getSQLState()).c_str()); 
     exit(EXIT_FAILURE); 
    } 
    return true; 
} 

bool delete_video(config_t *conf){ 
    try{ 
     sql::mysql::MySQL_Driver *driver; 
     sql::Connection *con; 
     sql::Statement *stmt; 
     sql::ResultSet *res; 
     sql::ResultSet *subres; 

     driver = sql::mysql::get_mysql_driver_instance(); 
     con = driver->connect(conf->sql_host, conf->sql_user, conf->sql_pass); 
     stmt = con->createStatement(); 
     stmt->execute("USE " + conf->sql_db); 

     std::string query = "SELECT monitor, recording_days FROM " + conf->sql_ev_videxp + " WHERE 1"; 

     //syslog (LOG_DEBUG, "Mysql Query: %s", query.c_str()); 

     res = stmt->executeQuery(query); 


     // SELECT Id, MonitorId, StartTime FROM Events WHERE StartTime < NOW() - INTERVAL 1 DAY ORDER BY Id ASC LIMIT 1 
     // SELECT Id, MonitorId, StartTime FROM Events WHERE StartTime LIKE "%2015-11-18%" and MonitorId = 56 
     // conf.dir_ev + "/" + MonitorId + "/" + todir(StartTime) 

     while (res->next()) { 
      int id = res->getInt("Id"); 
      int r_days = res->getInt("recording_days"); 

      //syslog (LOG_DEBUG, "Id: %i, Recording Days: %i", id, r_days); 

      std::stringstream subQuerySS; 
      subQuerySS << "SELECT id, file FROM " << conf->sql_ev_vid << " WHERE date < NOW() - INTERVAL " << r_days << " DAY AND monitor = " << id; 
      std::string subQuery = subQuerySS.str(); 
      subQuerySS.clear(); 

      //syslog (LOG_DEBUG, "Mysql Query: %s", subQuery.c_str()); 

      subres = stmt->executeQuery(subQuery); 

      while (subres->next()) { 
       int subid = subres->getInt("id"); 
       std::string file = subres->getString("file"); 

       std::string cmd = "rm -f " + file; 
       syslog (LOG_DEBUG, "%s", cmd.c_str()); 
       std::system(cmd.c_str()); 

       std::stringstream delQuerySS; 
       delQuerySS << "DELETE FROM " << conf->sql_ev_vid << " WHERE id = " << subid; 
       std::string delQuery = delQuerySS.str(); 
       delQuerySS.clear(); 

       syslog (LOG_DEBUG, "Mysql Query: %s", delQuery.c_str()); 

       stmt->execute(delQuery); 
      } 

     } 
     delete res; 
     delete subres; 
     delete stmt; 
     delete con; 
    } 
    catch(sql::SQLException &e){ 
     syslog (LOG_ERR, "Mysql Exception: %s, ERRNO %i, MySQL State: %s", e.what(), e.getErrorCode(), std::string(e.getSQLState()).c_str()); 
     exit(EXIT_FAILURE); 
    } 
    return true; 
} 

void signalHandler(int signum){ 
    syslog (LOG_NOTICE, "signal received (%i)", signum); 

    closelog(); 

    exit(signum); 
} 

int main(void) { 

     /* Our process ID and Session ID */ 
     pid_t pid, sid; 


     /* Fork off the parent process */ 
     pid = fork(); 
     if (pid < 0) { 
       exit(EXIT_FAILURE); 
     } 
     /* If we got a good PID, then 
      we can exit the parent process. */ 
     if (pid > 0) { 
       std::ofstream pid_file; 
       pid_file.open("evmanager.pid", std::ofstream::trunc); 
        if(pid_file.is_open()){ 
         pid_file << pid; 
         pid_file.close(); 
        } 

       exit(EXIT_SUCCESS); 
     } 

     /* Change the file mode mask */ 
     umask(0); 

     setlogmask (LOG_UPTO (LOG_DEBUG)); 

     openlog ("dt_event_manager", LOG_PID, LOG_DAEMON); 

     syslog (LOG_NOTICE, "Program started by User %d", getuid()); 

     /* Create a new SID for the child process */ 
     sid = setsid(); 
     if (sid < 0) { 
       syslog (LOG_ERR, "SID Creation Failed"); 
       exit(EXIT_FAILURE); 
     } 



     /* Change the current working directory */ 
     if ((chdir("/")) < 0) { 
       syslog (LOG_ERR, "Failed while Changing directory to /"); 
       exit(EXIT_FAILURE); 
     } 

     /* Read Initial Configuration */ 
     std::ifstream conf_file; 
     std::string line; 
     config_t conf; 

     conf_file.open("/etc/zm/evmanager.conf"); 
     if(conf_file.is_open()){ 
      while(std::getline(conf_file, line)){ 
       if(line[0] == '#')continue; 
       std::istringstream is_line(line); 
       std::string key; 
       if(std::getline(is_line, key, '=')){ 
        std::string value; 
        if(std::getline(is_line, value)){ 
         trim(key); 
         trim(value); 
         if(key == "sql_host")conf.sql_host = value; //mysql host 
         else if(key == "sql_user")conf.sql_user = value; //mysql user 
         else if(key == "sql_pass")conf.sql_pass = value; //mysql password 
         else if(key == "sql_db")conf.sql_db = value; //zoneminder database name 
         else if(key == "sql_ev_zm")conf.sql_ev_zm = value; //zoneminder events table 
         else if(key == "sql_ev_vid")conf.sql_ev_vid = value; //video events table 
         else if(key == "sql_ev_videxp")conf.sql_ev_videxp = value; //Zoneminder videos expiration directory 
         else if(key == "sql_mon")conf.sql_mon = value; //Zoneminder Monitors directory 
         else if(key == "dir_ev")conf.dir_ev = value; //Zoneminder events directory 
         else if(key == "dir_vid")conf.dir_vid = value; //Manager Videos directory 
         else if(key == "dir_ram")conf.dir_ram = value; //Ramfs mount dir 
         else if(key == "ram_size")conf.ram_size = value; //Ramfs size 
         else{ 
          syslog (LOG_ERR, "Bad config readout"); 
          exit(EXIT_FAILURE); 
         } 
        } 
       } 
      } 
     } 
     else{ 
      syslog (LOG_ERR, "Failed to open configuration file"); 
      exit(EXIT_FAILURE); 
     } 


     /* Close out the standard file descriptors */ 
     close(STDIN_FILENO); 
     close(STDOUT_FILENO); 
     close(STDERR_FILENO); 

     /* Daemon-specific initialization goes here */ 

     /* The Big Loop */ 

     signal(SIGINT, signalHandler); 

     syslog (LOG_INFO, "Daemon Started"); 

     while (1) { 
      make_video(); 
      delete_video(); 

      sleep(10); /* wait 10 seconds */ 
     } 
    exit(EXIT_SUCCESS); 
} 
+2

不能讓1個程序具有啓動參數並啓動它兩次嗎? – guiguiblitz

+0

從來沒有想到,輝煌!但是這是一個linux服務,所以我不知道如何退出父進程並使用相同的參數啓動子進程,生病必須做一些測試。 – Arheisel

+1

請發送代碼,現在還不清楚。 – 2016-05-12 14:11:43

回答

2

這是一個很好的問題。我實際上與學生解決了這個問題,因爲我是一名C++導師。

舉個例子,比方說,如果這是你的主:

//main.cpp: 
#include <iostream> 
#include "add.h" /// This comes in later :) 

using namespace std; 
int main() 
{ 
    cout << "2+3=" << add(2,3) << endl; 
    return 0; 
} 

您需要爲附加功能的頭文件,如:

//add.h 
#ifndef ADD_H_INCLUDED 
#define ADD_H_INCLUDED 
int add(int a, int b); 
#endif // ADD_H_INCLUDED 

但隨後你需要實際上定義什麼附加功能實際上做:

//add.cpp 
#include "add.h" 
int add(int a, int b) { 
    return a + b; 
} 

現在你可以選擇把多種功能我一個單獨的頭文件,或者每個函數都可以有它自己的頭文件,但這是你的選擇:)我希望這有助於!

+0

謝謝!我需要對g ++命令進行某種考慮嗎? – Arheisel

+0

爲了編譯它,使用:「g ++ main.cpp add.cpp」,它應該可以工作。不要編譯頭文件。 –

+0

我們從不編譯.h文件。如果你這樣做,它可能會編譯,但它會給你一個你不能使用的垃圾文件。用g ++,只需編譯.cpp文件。 –

2

您有多個選項。最簡單的是創建多個文件,或許是這樣的:

shared_header.hpp 
shared_functionality.cpp 
prog_a.cpp 
prog_b.cpp 

然後程序的編譯與源prog_a.cpp和shared_functionality.cpp和程序B與源prog_b.cpp和shared_functionality.cpp編譯。所有源文件都包含頭文件,而prog_a.cpp和prog_b.cpp各自定義了各自的main函數。

相關問題