From 6004d95868fcd9badbc0f026980a4a3597eb22db Mon Sep 17 00:00:00 2001
From: Thomas Guyot-Sionnest <dermoth@users.sourceforge.net>
Date: Sat, 15 Mar 2008 04:51:45 +0000
Subject: This commit consist of two changes: 1. Make np_get_defaults return a
 linked list instead of a string. It will then be easy to convert the linked
 list back to an argument array. 2. Fix tests 3-4 of test_ini.c.

A test_ini.t was added too. parse_ini and test_ini aren't included yet in the build makefiles.


git-svn-id: https://nagiosplug.svn.sourceforge.net/svnroot/nagiosplug/nagiosplug/trunk@1945 f882894a-f735-0410-b71e-b25c423dba1c

diff --git a/lib/parse_ini.c b/lib/parse_ini.c
index ef56be9..c915d79 100644
--- a/lib/parse_ini.c
+++ b/lib/parse_ini.c
@@ -42,9 +42,9 @@ typedef struct {
 #define GOBBLE_TO(f, c, n) do { (c)=fgetc((f)); } while((c)!=EOF && (c)!=(n))
 
 /* internal function that returns the constructed defaults options */
-static char* read_defaults(FILE *f, const char *stanza);
+static np_arg_list* read_defaults(FILE *f, const char *stanza);
 /* internal function that converts a single line into options format */
-static int add_option(FILE *f, char **optbuf, size_t *bufsize);
+static int add_option(FILE *f, np_arg_list **optlst);
 
 /* parse_locator decomposes a string of the form
  * 	[stanza][@filename]
@@ -76,9 +76,9 @@ static void parse_locator(const char *locator, const char *def_stanza, np_ini_in
 }
 
 /* this is the externally visible function used by plugins */
-char* np_get_defaults(const char *locator, const char *default_section){
+np_arg_list* np_get_defaults(const char *locator, const char *default_section){
 	FILE *inifile=NULL;
-	char *defaults=NULL;
+	np_arg_list *defaults=NULL;
 	np_ini_info i;
 
 	parse_locator(locator, default_section, &i);
@@ -104,10 +104,10 @@ char* np_get_defaults(const char *locator, const char *default_section){
  * be extra careful about user-supplied input (i.e. avoiding possible
  * format string vulnerabilities, etc)
  */
-static char* read_defaults(FILE *f, const char *stanza){
+static np_arg_list* read_defaults(FILE *f, const char *stanza){
 	int c;
-	char *opts=NULL;
-	size_t i, stanza_len, opts_buf_size=0;
+	np_arg_list *opts=NULL;
+	size_t i, stanza_len;
 	enum { NOSTANZA, WRONGSTANZA, RIGHTSTANZA } stanzastate=NOSTANZA;
 
 	stanza_len=strlen(stanza);
@@ -154,7 +154,7 @@ static char* read_defaults(FILE *f, const char *stanza){
 					/* okay, this is where we start taking the config */
 					case RIGHTSTANZA:
 						ungetc(c, f);
-						if(add_option(f, &opts, &opts_buf_size)){
+						if(add_option(f, &opts)){
 							die(STATE_UNKNOWN, _("Config file error"));
 						}
 						break;
@@ -170,15 +170,14 @@ static char* read_defaults(FILE *f, const char *stanza){
  * 	^option[[:space:]]*(=[[:space:]]*value)?
  * and creates it as a cmdline argument
  * 	--option[=value]
- * appending it to the string pointed to by optbuf (which will
- * be dynamically grown if needed)
+ * appending it to the linked list optbuf.
  */
-static int add_option(FILE *f, char **optbuf, size_t *bufsize){
-	char *newbuf=*optbuf;
+static int add_option(FILE *f, np_arg_list **optlst){
+	np_arg_list *opttmp=*optlst, *optnew;
 	char *linebuf=NULL, *lineend=NULL, *optptr=NULL, *optend=NULL;
 	char *eqptr=NULL, *valptr=NULL, *spaceptr=NULL, *valend=NULL;
 	short done_reading=0, equals=0, value=0;
-	size_t cfg_len=0, read_sz=8, linebuf_sz=0, read_pos=0, bs=*bufsize;
+	size_t cfg_len=0, read_sz=8, linebuf_sz=0, read_pos=0;
 	size_t opt_len=0, val_len=0;
 
 	/* read one line from the file */
@@ -214,14 +213,13 @@ static int add_option(FILE *f, char **optbuf, size_t *bufsize){
 	if(optptr==eqptr) die(STATE_UNKNOWN, _("Config file error\n"));
 	/* continue from '=' to start of value or EOL */
 	for(valptr=eqptr+1; valptr<lineend && isspace(*valptr); valptr++);
-	/* continue to the end of value, watching for trailing space/comments */
-	for(valend=valptr; valend<lineend; valend++){
-		if(isspace(*valend) && spaceptr==NULL) spaceptr=valend;
-		else if(*valend=='#') break;
-		else spaceptr=NULL;
-	}
-	if(spaceptr!=NULL) valend=spaceptr;
+	/* continue to the end of value (FIXME: watching for trailing comments) */
+	for(valend=valptr; valend<lineend; valend++)
+		/* FIXME: N::P doesn't allow comments. Remove next line and parse_ini won't either */
+		if(*valend=='#') break;
 	--valend;
+	/* Finally trim off trailing spaces */
+	for(valend; isspace(*valend); valend--);
 	/* calculate the length of "--foo" */
 	opt_len=1+optend-optptr;
 	cfg_len=2+(opt_len);
@@ -237,27 +235,31 @@ static int add_option(FILE *f, char **optbuf, size_t *bufsize){
 		cfg_len+=1;
 	}
 
-	/* okay, now we have all the info we need, so we grow the default opts
-	 * buffer if it's necessary, and put everything together.
-	 * (+2 is for a potential space and a null byte)
+	/* okay, now we have all the info we need, so we create a new np_arg_list
+	 * element and set the argument...
 	 */
-	read_pos=(newbuf==NULL)?0:strlen(newbuf);
-	if(newbuf==NULL || read_pos+cfg_len+2 >= bs){
-		bs=(bs>0)?(bs+cfg_len+2)<<1:cfg_len+1;
-		newbuf=realloc(newbuf, bs);
-		if(newbuf==NULL) die(STATE_UNKNOWN, _("malloc() failed!\n"));
-	}
-	if(read_pos>0) newbuf[read_pos++]=' ';
-	strncpy(&newbuf[read_pos], "--", 2); read_pos+=2;
-	strncpy(&newbuf[read_pos], optptr, opt_len); read_pos+=opt_len;
-	if(equals) newbuf[read_pos++]='=';
+	optnew=(np_arg_list *)malloc(sizeof(np_arg_list));
+	optnew->next=NULL;
+
+	read_pos=0;
+	optnew->arg=(char *)malloc(cfg_len+1);
+	strncpy(&optnew->arg[read_pos], "--", 2); read_pos+=2;
+	strncpy(&optnew->arg[read_pos], optptr, opt_len); read_pos+=opt_len;
+	if(equals) optnew->arg[read_pos++]='=';
 	if(value) {
-		strncpy(&newbuf[read_pos], valptr, val_len); read_pos+=val_len;
+		strncpy(&optnew->arg[read_pos], valptr, val_len); read_pos+=val_len;
 	}
-	newbuf[read_pos]='\0';
+	optnew->arg[read_pos]='\0';
 
-	*optbuf=newbuf;
-	*bufsize=bs;
+	/* ...and put that to the end of the list */
+	if (*optlst==NULL) {
+		*optlst=optnew;
+	}	else {
+		while (opttmp->next!=NULL) {
+			opttmp=opttmp->next;
+		}
+		opttmp->next = optnew;
+	}
 
 	free(linebuf);
 	return 0;
diff --git a/lib/parse_ini.h b/lib/parse_ini.h
index 1c28c7d..fea745c 100644
--- a/lib/parse_ini.h
+++ b/lib/parse_ini.h
@@ -6,6 +6,13 @@
  * configuration files.
  */
 
+/* np_arg_list is a linked list of arguments passed between the ini
+ * parser and the argument parser to construct the final array */
+typedef struct np_arg_el {
+	char *arg;
+	struct np_arg_el *next;
+} np_arg_list;
+
 /* NP_DEFAULT_INI_PATH: compile-time default location for ini file */
 #ifndef NP_DEFAULT_INI_PATH
 # define NP_DEFAULT_INI_PATH "/etc/nagios-plugins/plugins.ini"
@@ -14,6 +21,6 @@
 /* np_load_defaults: load the default configuration (if present) for
  * a plugin from the ini file
  */
-char* np_get_defaults(const char *locator, const char *default_section);
+np_arg_list* np_get_defaults(const char *locator, const char *default_section);
 
 #endif /* _PARSE_INI_H_ */
diff --git a/lib/tests/test_ini.c b/lib/tests/test_ini.c
index 302a2e5..b02d145 100644
--- a/lib/tests/test_ini.c
+++ b/lib/tests/test_ini.c
@@ -19,6 +19,7 @@
 
 #include "common.h"
 #include "parse_ini.h"
+#include "utils_base.h"
 
 #include "tap.h"
 
@@ -29,6 +30,22 @@ void my_free(char *string) {
 	}
 }
 
+char*
+list2str(np_arg_list *optlst)
+{
+	char *optstr=NULL;
+
+	/* Put everything as a space-separated string */
+	while (optlst) {
+		asprintf(&optstr, "%s%s ", optstr?optstr:"", optlst->arg);
+		optlst=optlst->next;
+	}
+	/* Strip last whitespace */
+	optstr[strlen(optstr)-1]='\0';
+
+	return optstr;
+}
+
 int
 main (int argc, char **argv)
 {
@@ -36,11 +53,11 @@ main (int argc, char **argv)
 
 	plan_tests(4);
 
-	optstr=np_get_defaults("section@./config-tiny.ini", "check_disk");
+	optstr=list2str(np_get_defaults("section@./config-tiny.ini", "check_disk"));
 	ok( !strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank="), "config-tiny.ini's section as expected");
 	my_free(optstr);
 
-	optstr=np_get_defaults("@./config-tiny.ini", "section");
+	optstr=list2str(np_get_defaults("@./config-tiny.ini", "section"));
 	ok( !strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank="), "Used default section name, without specific");
 	my_free(optstr);
 
@@ -51,7 +68,7 @@ main (int argc, char **argv)
 	my_free(optstr);
 	*/
 
-	optstr=np_get_defaults("Section Two@./config-tiny.ini", "check_disk");
+	optstr=list2str(np_get_defaults("Section Two@./config-tiny.ini", "check_disk"));
 	ok( !strcmp(optstr, "--something else=blah --remove=whitespace"), "config-tiny.ini's Section Two as expected");
 	my_free(optstr);
 
@@ -70,7 +87,7 @@ main (int argc, char **argv)
 	my_free(optstr);
 	*/
 
-	optstr=np_get_defaults("check_mysql@./plugin.ini", "check_disk");
+	optstr=list2str(np_get_defaults("check_mysql@./plugin.ini", "check_disk"));
 	ok( !strcmp(optstr, "--username=operator --password=secret"), "plugin.ini's check_mysql as expected");
 	my_free(optstr);
 
diff --git a/lib/tests/test_ini.t b/lib/tests/test_ini.t
new file mode 100755
index 0000000..b130a01
--- /dev/null
+++ b/lib/tests/test_ini.t
@@ -0,0 +1,6 @@
+#!/usr/bin/perl
+use Test::More;
+if (! -e "./test_ini") {
+	plan skip_all => "./test_ini not compiled - please install tap library to test";
+}
+exec "./test_ini";
-- 
cgit v0.10-9-g596f

