⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 configfile.cpp

📁 一个Linux下读写文件的代码
💻 CPP
字号:
/*  The following is the Simplified BSD License *  * Copyright (c) 2008, Warren Kurt vonRoeschlaub * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions  * are met: *  *  * Redistributions of source code must retain the above copyright  *       notice, this list of conditions and the following disclaimer. *  * Redistributions in binary form must reproduce the above copyright  *       notice, this list of conditions and the following disclaimer  *       in the documentation and/or other materials provided with the  *       distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "configfile.h"#include "configitem_base.h"#include <fstream>#include <iostream>namespace configlib{/* * The following are used by command line processing. */	#define CHAR_DASH '-'#define CHAR_EQUALS '='/* * Constructor - assigns a file name */configfile::configfile(const std::string& file_name): fileName(file_name){}/* * Destructor - */configfile::~configfile(){}/* * read - reads and parses the configuration file. */void configfile::read(){	std::string line;    std::ifstream fileStream(fileName.c_str());    if (fileStream)    {        while(getline(fileStream, line))        {            data.push_back(line);        }                fileStream.close();    }        // Now parse everything into the attatched objects.    parse();}/* * write - Writes the updated configuration file. */void configfile::write(){    std::ofstream fileStream(fileName.c_str(), std::ofstream::trunc);    if (fileStream) {        std::vector<std::string>::iterator it;        for (it = data.begin();it != data.end();it++)        {            fileStream << (*it) << std::endl;        }                fileStream.close();    }}/* * parse - parses the command line.  The caller is responsible for error * 		checking.  The return value is any erro that may have ocurred. *   ERROR_NONE    - No error. *   ERROR_UNKNOWN - An unknown parameter was passed. *   ERROR_MISSING - A parameter was needed but missing. *   ERROR_EXTRA   - Too many unswitched paremeters.  * Note: ERROR_EXTRA is used internally to signal the subroutines to * 		increment.  These cases do not result in an actual error. */int configfile::parse(int argc, char *argv[]){	// For simplicity's sake, the configfile object tracks the name of	// the program.	prog_name = argv[0];		// Now parse each argument.  Config items are scanned using simple	// rules for command line parameters defined as follows:	//   A character - The object uses that character	//   A digit - The object uses the unswitched parameter with that index (starting with 0)	//   A dash - the object uses the standard long-name format of two	//			dashes followed by the configuration file name with any	//			spaces in the name replaced with dashes.	// One or more of the following can be appended to the string	//   A dash - The object uses the character or the long-name	//			convention as above.	//   An equal sign - For a single character the next parameter will be	//			used, for a long name anything after the = will be used.	int err;	int index = 1;	int parm_index = 0;	while (index < argc)	{		if (CHAR_DASH == argv[index][0])		{			if (CHAR_DASH == argv[index][1])			{				// Long-name parameter				err = parse_long(&(argv[index][2]));				if (ERROR_NONE != err)					return err;			}			else			{				// single character parameter (may be multiple)				for (int count = 1;0 != argv[index][count];count++)				{					err = parse_char(argv[index][count], ((index + 1) < argc) ? argv[index + 1] : NULL);					if (ERROR_UNKNOWN == err)						return err;					else if (ERROR_EXTRA == err)					{						index++;						break;					}				}			}		}		else		{			// Indexed parameter			if (parm_index > 9)				return ERROR_EXTRA;			err = parse_index(parm_index, argv[index]);			if (ERROR_NONE != err)				return err;			parm_index++;		}			index++;		}		return ERROR_NONE; }/* * parse - parse the configuration file.  Parsing is done by interating over the * 		configuration file settings and passing them to each item until it finds * 		one that returns true - a signal that the item processes the configuration *      setting. */void configfile::parse(){	iterator it(data);	while (!it.end())	{		std::string name = it.get_name();		std::string value = it.get_value();		for (std::vector<configitem_base*>::iterator vit = item_list.begin();		     item_list.end() != vit;vit++)		{			if (0 < value.length())			{				if ((*vit)->parse(it.get_section(), name, value))					break;			}			else if ((*vit)->parse(it.get_section(), name))				break;		}		it++;	}}/* * parse - parse a single item from the configuration file.  This iterates over * 		the configuration file items looking for one the passed item processes. * 		Sometimes the item needs to read more than one line, so do not stop *      processing until the end of the file is reached. */void configfile::parse(configitem_base* item){	iterator it(data);	while (!it.end())	{		std::string name = it.get_name();		std::string value = it.get_value();		if (0 < value.length())			item->parse(it.get_section(), name, value);		else			item->parse(it.get_section(), name);		it++;	}}/* * parse_char - parse a single character command line parameter */int configfile::parse_char(char item, const std::string& next){	std::vector<configitem_base*>::iterator it;	for (it = item_list.begin();item_list.end() != it;it++)	{		if ((*it)->get_param().find(item) != std::string::npos)		{			if ((*it)->get_param().find(CHAR_EQUALS) != std::string::npos)			{				(*it)->parse(next);				return ERROR_EXTRA;			}			else			{				// It is just switched, toggle it				(*(*it))++;				return ERROR_NONE;			}		}	}		return ERROR_UNKNOWN;}/* * parse_long - parse a long-name command line parameter */int configfile::parse_long(const std::string& name){	std::size_t pos = name.find(CHAR_EQUALS);	std::string compare = name.substr(0, pos);		// Convert the passed name by removing the dashes that	// are standard in long-name parameters.	pos = compare.find(' ');	while (std::string::npos != pos)	{		compare.replace(pos, 1, 1, CHAR_DASH);		pos = compare.find(' ');	}		// Iterate over the stored items and find any match.	std::vector<configitem_base*>::iterator it;	for (it = item_list.begin();item_list.end() != it;it++)	{		// Only items with a dash in their parameter field can use		// long names.		if ((*it)->get_param().find(CHAR_DASH) != std::string::npos)		{			// If there is an equals in the parameter field, then the			// value should be an assignment.			if ((*it)->get_param().find(CHAR_EQUALS) != std::string::npos)			{				if ((std::string::npos != pos) &&					((*it)->get_name() == name.substr(0, pos)))				{					(*it)->parse(name.substr(pos + 1));					return ERROR_NONE;				}				else if ((*it)->get_name() == name)				{					// There was no data despite the need for it.  Fail with error.					return ERROR_MISSING;				}			}			else if ((*it)->get_name() == name)			{				// It is just switched, so toggle it.				(*(*it))++;				return ERROR_NONE;			}		}	}		return ERROR_UNKNOWN;}/* * parse_index - parse an unswitched parameter from the command line based on index */int configfile::parse_index(int index, const std::string& next){	std::vector<configitem_base*>::iterator it;	for (it = item_list.begin();item_list.end() != it;it++)	{		// This code only allows 10 unswitched parameters		if ((*it)->get_param().find((char)(index + '0')) != std::string::npos)		{			(*it)->parse(next);			return ERROR_NONE;		}	}		return ERROR_EXTRA;}/* * clear - comment out a parameter in the loaded config file */void configfile::clear(const std::string& section, const std::string& name){	iterator it(data);	while (!it.end())	{		if (match(section.c_str(), it.get_section().c_str()) &&	        match(name.c_str(), it.get_name().c_str()))	    {			it.insert(0, "#");			break;		}		it++;    }}/* * set - set the value of an item in the loaded configuration file */void configfile::set(const std::string& section, const std::string& name, const std::string& value){	iterator it(data);	while (!it.end())	{		if (match(section.c_str(), it.get_section().c_str()) &&	        match(name.c_str(), it.get_name().c_str()))	    {	    	it.replace_value(value);			return;		}		it++;    }	// If we get here the line does not exist (or is commented out).  Find the start of	// the section, and insert the name/value pair.	std::string item = name;	item.append("=");	item.append(value);	add(section, item);}/* * add - add a line to a section in the config file */void configfile::add(const std::string& section, const std::string& line){	iterator it(data);	while (!it.end())	{		if (match(section.c_str(), it.get_section().c_str()))	    {	    	// Find start of next section and/or end of file	    	iterator last = it;	    	while (!it.end() && match(section.c_str(), it.get_section().c_str()))	    	{	    		last = it;	    		it++;	    	}	    		    	// At the end of the file, append, otherwise insert immediately after	    	// the line currently pointed at.	    	if (it.end())	    		data.push_back(line);	    	else	    		data.insert(last.get_next(), line);			return;		}		it++;    }        // If we get here, even the section does not exist.    std::string item = "[";    item.append(section);    item.append("]");    data.push_back(item);    data.push_back(line);}/* * erase - unlink a configuration item from the configuration file */void configfile::erase(configitem_base* item){	std::vector<configitem_base*>::iterator it = item_list.begin();	while (item_list.end() != it)	{		if ((*it) == item)		{			item_list.erase(it);			break;		}		it++;	}}/* * match - return true if the two strings match */bool configfile::match(const char* pattern, const char* data){	// Compare strings for exact match	// TODO: Do we need to double check this for buffer overflow?  Who's	// calling this?	if (0 == strcmp(pattern, data))		return true;		// TODO: add regex matching.	// For now, just match wildcards	if ('*' == pattern[0])		return true;		return false;}/* * Constructor - create the fake internal iterator for the configuration */configfile::iterator::iterator(std::vector<std::string>& source){	data = &source;	index = data->begin();	while(parse())		index++;}/* * get_name - return the name of the current setting in the config file */ const std::string configfile::iterator::get_name(){	std::size_t pos = (*index).find('=');	if (std::string::npos != pos)		return (*index).substr(0, pos);	else		return (*index);}/* * get_value - return the value of the current setting in the config file */const std::string configfile::iterator::get_value(){	std::size_t pos = (*index).find('=');	if (std::string::npos != pos)		return (*index).substr(pos + 1);	else		return "";}/* * replace_value - replace the value in the line the iterator currently points  * 			to with a new value. */void configfile::iterator::replace_value(const std::string& value){	std::size_t pos = index->find('=');	*index = index->substr(0, pos + 1);	index->append(value);}/* * operator= - duplicate the fake iterator */configfile::iterator& configfile::iterator::operator=(const configfile::iterator& rhs){	section = rhs.section;	data = rhs.data;	index = rhs.index;	return *this;}/* * operator++ - increment the iterator to the next config file setting. */configfile::iterator& configfile::iterator::operator++(){	if (data->end() != index)	{		do		{			index++;		} while (parse());	}		return *this;}/* * parse - advance the line pointer, return true if it needs to be parsed again * 			to point at a valid configuration line */bool configfile::iterator::parse(){	if (data->end() == index)		return false; // Reached the end.		std::size_t start = (*index).find_first_not_of(" \t");	if (std::string::npos == start)		return true; // Blank line;	else if ('#' == (*index).at(start))		return true;  // Comments are not parsed	else if ('[' == (*index).at(start))	{		// Section header		std::size_t end = (*index).find(']');		section = (*index).substr(start + 1, end - 1);		return true; // Section headers are not data.	}	else		return false; // Found a statement}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -