"SfR Fresh" - the SfR Freeware/Shareware Archive

Member "brutus-server/config.cpp" of archive brutus-server-1.0.0.tar.gz:


As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
    1 /*
    2  *    Brutus source file implementing a configuration file class.
    3  *    Copyright (C) 2004 OMC Denmark ApS.
    4  *
    5  *    This program is free software; you can redistribute it and/or modify
    6  *    it under the terms of the GNU General Public License as published by
    7  *    the Free Software Foundation; either version 2 of the License, or
    8  *    (at your option) any later version.
    9  *
   10  *    This program is distributed in the hope that it will be useful,
   11  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13  *    GNU General Public License for more details.
   14  *
   15  *    You should have received a copy of the GNU General Public License
   16  *    along with this program; if not, write to the Free Software
   17  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   18  */
   19 
   20 #include "config.h"
   21 #include <fcntl.h>
   22 #include <io.h>
   23 #include <sys/stat.h>
   24 #include <ctype.h>
   25 #include <stdio.h>
   26 
   27 #ifdef COMMENT_CHAR
   28 #undef COMMENT_CHAR
   29 #endif
   30 #define COMMENT_CHAR '#'
   31 
   32 #ifdef MAX_CONFIG_FILE_SIZE
   33 #undef MAX_CONFIG_FILE_SIZE
   34 #endif
   35 #define MAX_CONFIG_FILE_SIZE (20480)
   36 
   37 /* Will load the configuration file "file". Returns
   38  * zero on success or a positive number which indicates
   39  * a faulty configuration line or a negative number
   40  * which indicates that the configuration file is to
   41  * big or can not be read. */
   42 int Config::load(const char *file)
   43 {
   44 	if (!file)
   45 		return -1;
   46 
   47 	// initialize
   48 	if (_items) {
   49 		free(_items);
   50 		_items = NULL;
   51 	}
   52 	if (_fbuf) {
   53 		free(_fbuf);
   54 		_fbuf = NULL;
   55 	}
   56 	_lnum = 1;
   57 
   58 	// read file into buffer
   59 	if (read_conf(file, &_fsize, (void**)&_fbuf))
   60 		return -1;
   61 
   62 	return itemize();
   63 }
   64 
   65 int Config::itemize(void)
   66 {
   67 	size_t count = 0;
   68 	char *p = _fbuf;
   69 
   70 	// count maximum number of effective configuration lines
   71 	for (size_t n = 0; n < _fsize; n++, p++) {
   72 		// newline?
   73 		if (*p == '\0')
   74 			count++;
   75 	}
   76 	_items = (struct item*)malloc(sizeof(struct item) * (count + 1));
   77 
   78 	// get token/value pairs
   79 	p = _fbuf;
   80 	count = 0;
   81 	if ((wspace(*p)) || (*p == COMMENT_CHAR))
   82 		if (get_next_line(&p))
   83 			return _lnum;
   84 	while (1) {
   85 		if (!p)
   86 			break;
   87 
   88 		_items[count].token = p;
   89 
   90 		// p will be somewhere within the value string when the function returns
   91 		if (point_to_value(&p, &_items[count++].value))
   92 			return _lnum;
   93 
   94 		if (get_next_line(&p))
   95 			return _lnum;
   96 	}
   97 	_items[count].token = NULL;
   98 	_items[count].value = NULL;
   99 
  100 	return 0;
  101 }
  102 
  103 /* Upon return val points to the first character in the null-
  104  * or whitespace-terminated value string.
  105  *
  106  * *str is a pointer to the first character in a null-terminated
  107  * configuration line.
  108  *
  109  * *str is modified by this function to point to the first
  110  * character in the value string.
  111  *
  112  * Will return (-1) on error or zero on success. */
  113 int Config::point_to_value(char **str, char **val)
  114 {
  115 	// not possible
  116 	if (wspace(**str))
  117 		return -1;
  118 
  119 	// skip past token
  120 	while ((!wspace(**str)) && (**str != '\0')) {
  121 		(*str)++;
  122 	}
  123 	if (**str == '\0')
  124 		return -1;
  125 
  126 	// skip past whitespace to value
  127 	while (wspace(**str)) {
  128 		**str = '\0';
  129 		(*str)++;
  130 	}
  131 	if (**str == '\0')
  132 		return -1;
  133 
  134 	*val = *str;
  135 
  136 	// remove trailing whitespace
  137 	char *tmp = *val;
  138 	while (*tmp != '\0')
  139 		tmp++;
  140 	tmp--;
  141 	while (wspace(*tmp)) {
  142 		*tmp = '\0';
  143 		tmp--;
  144 	}
  145 
  146 	return 0;
  147 }
  148 
  149 /* *str is a pointer to the first character
  150  * of the next configuration line skipping comments and
  151  * empty lines.
  152  *
  153  * *str is NULL on end-of-buffer.
  154  *
  155  * Returns (-1) on error or zero on success. */
  156 int Config::get_next_line(char **str)
  157 {
  158 	int retv = 0;
  159 	size_t offset = *str - _fbuf;
  160 
  161 	do {
  162 		// skip printable characters
  163 		while (**str != '\0') {
  164 			(*str)++;
  165 
  166 			offset++;
  167 			if (offset == _fsize) {
  168 				*str = NULL;
  169 				goto out;
  170 			}
  171 		}
  172 
  173 		// skip '\0's
  174 		while (**str == '\0') {
  175 			_lnum++;
  176 			(*str)++;
  177 
  178 			offset++;
  179 			if (offset == _fsize) {
  180 				*str = NULL;
  181 				goto out;
  182 			}
  183 		}
  184 
  185 		// quick check for floating text (<WHITESPACE>TEXT)
  186 		if (wspace(**str)) {
  187 			while (wspace(**str)) {
  188 				(*str)++;
  189 				offset++;
  190 				if (offset == _fsize) {
  191 					*str = NULL;
  192 					goto out;
  193 				}
  194 			}
  195 
  196 			// floating text
  197 			if (**str != '\0') {
  198 				retv = -1;
  199 				goto out;
  200 			}
  201 			continue;
  202 		}
  203 
  204 		// configuration line?
  205 		if (**str != COMMENT_CHAR)
  206 			break;
  207 	} while (1);
  208 
  209 out:
  210 	return retv;
  211 }
  212 
  213 /* Will return the corresponding value string or NULL
  214  * if non-existent. The token will be cleared if strip
  215  * is true. This makes multible like-named options
  216  * possible so as to sequentially read them all.
  217  *
  218  * The return value must be freed by callee. */
  219 char *Config::get_value(const char *token)
  220 {
  221 	size_t n = 0;
  222 
  223 	if (_items) {
  224 		while (_items[n].value) {
  225 			if ((_items[n].token) && !strcmp(token, _items[n].token)) {
  226 				if (_stack && !strcmp(token, _stack))
  227 					_items[n].token = NULL;
  228 				return _strdup(_items[n].value);
  229 			}
  230 			n++;
  231 		}
  232 	}
  233 
  234 	return NULL;
  235 }
  236 
  237 /* Reads all of file_name into *buf, as a set of adjoined
  238  * strings, correcting for CRLF.
  239  *
  240  * *size is the size of the file in bytes, not the size
  241  * of the buffer *buf. Callee must free() *buf if zero
  242  * is returned, otherwise not.
  243  *
  244  * I am reading one byte of the file at a time. This is to
  245  * avoid a second copy/allocation. Not that this method is
  246  * particular fast, but it makes the purpose so much clearer.
  247  * This function is not a bottleneck, therefore clarity before
  248  * speed.
  249  *
  250  * Returns -1 on error. */
  251 int Config::read_conf(const char *file_name, size_t *size, void **buf)
  252 {
  253 	FILE *file;
  254 	int retv = 0;
  255 	size_t len;
  256 	char *tmp;
  257 	char *first;
  258 	struct stat fstatus;
  259 
  260 
  261 	retv = stat(file_name, &fstatus);
  262 	if (retv)
  263 		return -1;
  264 
  265 	if (fstatus.st_size > MAX_CONFIG_FILE_SIZE)
  266 		return -1;
  267 
  268 	tmp = (char*)malloc(fstatus.st_size);
  269 	if (!tmp)
  270 		return -1;
  271 	memset((void*)tmp, '\0', fstatus.st_size);
  272 	first = tmp;
  273 
  274 	if (fopen_s(&file, file_name, "r")) {
  275 		free(tmp);
  276 		return -1;
  277 	}
  278 
  279 	char c;
  280 	off_t pos = 0;
  281 	while (1) {
  282 		// For clarity, not speed
  283 		len = fread((void*)&c, 1, 1, file);
  284 		if (!len) {
  285 			if (ferror(file))
  286 				retv = -1;
  287 			break;
  288 		}
  289 
  290 		// create null-terminated string
  291 		if (c == '\n') {
  292 			c = '\0';
  293 		}
  294 
  295 		// skip CR
  296 		if (c != '\r') {
  297 			*tmp = c;
  298 			pos++;
  299 			if (pos < fstatus.st_size)
  300 				tmp++;
  301 		}
  302 	}
  303 	if (file)
  304 		fclose(file);
  305 
  306 	if (retv)
  307 		free(tmp);
  308 	else {
  309 		*buf = first;
  310 		*size = pos;
  311 	}
  312 
  313 	return retv;
  314 }
  315 
  316 bool Config::get_token_value_pair(const char *token,
  317 				  const char *value)
  318 {
  319 	static size_t n = 0;
  320 
  321 	if (!_items[n].token)
  322 		return false;
  323 
  324 	token = _items[n].token;
  325 	value = _items[n].value;
  326 	n++;
  327 
  328 	return true;
  329 }