diff --git a/src/xpdev/ini_file.c b/src/xpdev/ini_file.c
index bd9ae304c27283a8f6ff893ab233defaa07bf54c..b84aa4466158c5f8919b47289b132969694cf733 100644
--- a/src/xpdev/ini_file.c
+++ b/src/xpdev/ini_file.c
@@ -44,6 +44,8 @@
 
 #define INI_MAX_LINE_LEN	256		/* Maximum length of entire line, includes '\0' */
 
+#define NEW_SECTION	((char*)~0)
+
 /****************************************************************************/
 /* Truncates white-space chars off end of 'str'								*/
 /****************************************************************************/
@@ -56,10 +58,27 @@ static void truncsp(char *str)
 	str[c]=0;
 }
 
+static char* section_name(char* p)
+{
+	char*	tp;
+
+	SKIP_WHITESPACE(p);
+	if(*p!='[')
+		return(NULL);
+	p++;
+	SKIP_WHITESPACE(p);
+	tp=strchr(p,']');
+	if(tp==NULL)
+		return(NULL);
+	*tp=0;
+	truncsp(p);
+
+	return(p);
+}
+
 static BOOL find_section(FILE* fp, const char* section)
 {
 	char*	p;
-	char*	tp;
 	char	str[INI_MAX_LINE_LEN];
 
 	rewind(fp);
@@ -67,25 +86,55 @@ static BOOL find_section(FILE* fp, const char* section)
 	while(!feof(fp)) {
 		if(fgets(str,sizeof(str),fp)==NULL)
 			break;
-		p=str;
-		while(*p && *p<=' ') p++;
-		if(*p!='[')
+		if((p=section_name(str))==NULL)
 			continue;
-		p++;
-		tp=strchr(p,']');
-		if(tp==NULL)
-			continue;
-		*tp=0;
 		if(stricmp(p,section)==0)
 			return(TRUE);
 	}
 	return(FALSE);
 }
 
+static size_t find_section_index(str_list_t list, const char* section)
+{
+	char*	p;
+	char	str[INI_MAX_VALUE_LEN];
+	size_t	i;
+
+	for(i=0; list[i]!=NULL; i++) {
+		SAFECOPY(str,list[i]);
+		if((p=section_name(str))!=NULL && stricmp(p,section)==0)
+			return(i+1);
+	}
+
+	return(i);
+}
+
+static char* key_name(char* p, char** vp)
+{
+	/* Parse value name */
+	SKIP_WHITESPACE(p);
+	if(*p==';')
+		return(NULL);
+	if(*p=='[')
+		return(NEW_SECTION);
+	*vp=strchr(p,'=');
+	if(*vp==NULL)
+		return(NULL);
+	*(*vp)=0;
+	truncsp(p);
+
+	/* Parse value */
+	(*vp)++;
+	SKIP_WHITESPACE(*vp);
+	truncsp(*vp);
+
+	return(p);
+}
+
 static char* get_value(FILE* fp, const char* section, const char* key, char* value)
 {
 	char*	p;
-	char*	tp;
+	char*	vp;
 	char	str[INI_MAX_LINE_LEN];
 
 	if(fp==NULL)
@@ -97,30 +146,151 @@ static char* get_value(FILE* fp, const char* section, const char* key, char* val
 	while(!feof(fp)) {
 		if(fgets(str,sizeof(str),fp)==NULL)
 			break;
-		p=str;
-		while(*p && *p<=' ') p++;
-		if(*p==';')
+		if((p=key_name(str,&vp))==NULL)
 			continue;
-		if(*p=='[')
+		if(p==NEW_SECTION)
 			break;
-		tp=strchr(p,'=');
-		if(tp==NULL)
-			continue;
-		*tp=0;
-		truncsp(p);
 		if(stricmp(p,key)!=0)
 			continue;
 		/* key found */
-		p=tp+1;
-		while(*p && *p<=' ') p++;
-		truncsp(p);
-		sprintf(value,"%.*s",INI_MAX_VALUE_LEN-1,p);
+		sprintf(value,"%.*s",INI_MAX_VALUE_LEN-1,vp);
 		return(value);
 	}
 
 	return(NULL);
 }
 
+static size_t find_value_index(str_list_t list, const char* section, const char* key)
+{
+	char	str[INI_MAX_LINE_LEN];
+	char*	p;
+	char*	vp;
+	size_t	i;
+
+	for(i=find_section_index(list, section); list[i]!=NULL; i++) {
+		SAFECOPY(str, list[i]);
+		if((p=key_name(str,&vp))==NULL)
+			continue;
+		if(p==NEW_SECTION)
+			break;
+		if(stricmp(p,key)==0)
+			return(i);
+	}
+
+	return(i);
+}
+
+size_t iniAddSection(str_list_t* list, const char* section)
+{
+	char	str[INI_MAX_LINE_LEN];
+	size_t	i;
+
+	i=find_section_index(*list, section);
+	if((*list)[i]==NULL) {
+		sprintf(str,"[%s]",section);
+		strListAppend(list, str, i);
+	}
+
+	return(i);
+}
+
+char* iniSetString(str_list_t* list, const char* section, const char* key, const char* value
+				 ,ini_style_t* style)
+{
+	char	str[INI_MAX_LINE_LEN];
+	size_t	i;
+
+	iniAddSection(list, section);
+
+	if(key==NULL)
+		return(NULL);
+	if(style->key_prefix==NULL)
+		style->key_prefix="";
+	if(style->value_separator==NULL)
+		style->value_separator="=";
+	sprintf(str, "%s%-*s%s%s", style->key_prefix, style->key_len, key, style->value_separator, value);
+	i=find_value_index(*list, section, key);
+	if((*list)[i]==NULL)
+		return strListInsert(list, str, i);
+
+	return strListReplace(*list, i, str);
+}
+
+char* iniSetInteger(str_list_t* list, const char* section, const char* key, long value
+					,ini_style_t* style)
+{
+	char	str[INI_MAX_VALUE_LEN];
+
+	sprintf(str,"%ld",value);
+	return iniSetString(list, section, key, str, style);
+}
+
+char* iniSetShortInt(str_list_t* list, const char* section, const char* key, ushort value
+					,ini_style_t* style)
+{
+	char	str[INI_MAX_VALUE_LEN];
+
+	sprintf(str,"%hu",value);
+	return iniSetString(list, section, key, str, style);
+}
+
+char* iniSetHexInt(str_list_t* list, const char* section, const char* key, ulong value
+					,ini_style_t* style)
+{
+	char	str[INI_MAX_VALUE_LEN];
+
+	sprintf(str,"0x%lx",value);
+	return iniSetString(list, section, key, str, style);
+}
+
+char* iniSetFloat(str_list_t* list, const char* section, const char* key, double value
+					,ini_style_t* style)
+{
+	char	str[INI_MAX_VALUE_LEN];
+
+	sprintf(str,"%g",value);
+	return iniSetString(list, section, key, str, style);
+}
+
+char* iniSetIpAddress(str_list_t* list, const char* section, const char* key, ulong value
+					,ini_style_t* style)
+{
+	struct in_addr in_addr;
+	in_addr.s_addr=value;
+	return iniSetString(list, section, key, inet_ntoa(in_addr), style);
+}
+
+char* iniSetBool(str_list_t* list, const char* section, const char* key, BOOL value
+					,ini_style_t* style)
+{
+	return iniSetString(list, section, key, value ? "true":"false", style);
+}
+
+char* iniSetBitField(str_list_t* list, const char* section, const char* key, ulong value
+					,ini_bitdesc_t* bitdesc, ini_style_t* style)
+{
+	char	str[INI_MAX_VALUE_LEN];
+	int		i;
+
+	if(style->bit_separator==NULL)
+		style->bit_separator="|";
+	str[0]=0;
+	for(i=0;bitdesc[i].name;i++) {
+		if((value&bitdesc[i].bit)==0)
+			continue;
+		if(str[0])
+			strcat(str,style->bit_separator);
+		strcat(str,bitdesc[i].name);
+		value&=~bitdesc[i].bit;
+	}
+	if(value) {	/* left over bits? */
+		if(str[0])
+			strcat(str,style->bit_separator);
+		sprintf(str+strlen(str), "0x%lX", value);
+	}
+	return iniSetString(list, section, key, str, style);
+}
+
 char* iniGetString(FILE* fp, const char* section, const char* key, const char* deflt, char* value)
 {
 	if(get_value(fp,section,key,value)==NULL || *value==0 /* blank */) {
@@ -188,7 +358,6 @@ void* iniFreeNamedStringList(named_string_t** list)
 str_list_t iniGetSectionList(FILE* fp, const char* prefix)
 {
 	char*	p;
-	char*	tp;
 	char	str[INI_MAX_LINE_LEN];
 	ulong	items=0;
 	str_list_t	lp;
@@ -204,15 +373,8 @@ str_list_t iniGetSectionList(FILE* fp, const char* prefix)
 	while(!feof(fp)) {
 		if(fgets(str,sizeof(str),fp)==NULL)
 			break;
-		p=str;
-		while(*p && *p<=' ') p++;
-		if(*p!='[')
+		if((p=section_name(str))==NULL)
 			continue;
-		p++;
-		tp=strchr(p,']');
-		if(tp==NULL)
-			continue;
-		*tp=0;
 		if(prefix!=NULL)
 			if(strnicmp(p,prefix,strlen(prefix))!=0)
 				continue;
@@ -226,7 +388,7 @@ str_list_t iniGetSectionList(FILE* fp, const char* prefix)
 str_list_t iniGetKeyList(FILE* fp, const char* section)
 {
 	char*	p;
-	char*	tp;
+	char*	vp;
 	char	str[INI_MAX_LINE_LEN];
 	ulong	items=0;
 	str_list_t	lp;
@@ -245,17 +407,10 @@ str_list_t iniGetKeyList(FILE* fp, const char* section)
 	while(!feof(fp)) {
 		if(fgets(str,sizeof(str),fp)==NULL)
 			break;
-		p=str;
-		while(*p && *p<=' ') p++;
-		if(*p==';')
+		if((p=key_name(str,&vp))==NULL)
 			continue;
-		if(*p=='[')
+		if(p==NEW_SECTION)
 			break;
-		tp=strchr(p,'=');
-		if(tp==NULL)
-			continue;
-		*tp=0;
-		truncsp(p);
 		if(strListAppend(&lp,p,items++)==NULL)
 			break;
 	}
@@ -266,10 +421,8 @@ str_list_t iniGetKeyList(FILE* fp, const char* section)
 named_string_t**
 iniGetNamedStringList(FILE* fp, const char* section)
 {
-	char*	p;
 	char*	name;
 	char*	value;
-	char*	tp;
 	char	str[INI_MAX_LINE_LEN];
 	ulong	items=0;
 	named_string_t** lp;
@@ -291,22 +444,10 @@ iniGetNamedStringList(FILE* fp, const char* section)
 	while(!feof(fp)) {
 		if(fgets(str,sizeof(str),fp)==NULL)
 			break;
-		p=str;
-		while(*p && *p<=' ') p++;
-		if(*p==';')
+		if((name=key_name(str,&value))==NULL)
 			continue;
-		if(*p=='[')
+		if(name==NEW_SECTION)
 			break;
-		tp=strchr(p,'=');
-		if(tp==NULL)
-			continue;
-		*tp=0;
-		truncsp(p);
-		name=p;
-		p=tp+1;
-		while(*p && *p<=' ') p++;
-		truncsp(p);
-		value=p;
 		if((np=realloc(lp,sizeof(named_string_t*)*(items+2)))==NULL)
 			break;
 		lp=np;
@@ -429,7 +570,7 @@ ulong iniGetBitField(FILE* fp, const char* section, const char* key,
 			break;
 
 		p=tp+1;
-		while(*p && *p<=' ') p++;
+		SKIP_WHITESPACE(p);
 	}
 
 	return(v);
@@ -442,7 +583,7 @@ str_list_t iniReadFile(FILE* fp)
 	
 	rewind(fp);
 
-	list = strListReadFile(fp, NULL, INI_MAX_VALUE_LEN, TRUE /* pad */);
+	list = strListReadFile(fp, NULL, INI_MAX_LINE_LEN, FALSE /* pad */);
 	if(list!=NULL) {
 		/* truncate the white-space off end of strings */
 		for(i=0; list[i]!=NULL; i++)
diff --git a/src/xpdev/ini_file.h b/src/xpdev/ini_file.h
index fcc452e69dca840b5af4cc4f4de5d54a00bc41ff..e1d6e329b6a581385ba161c9063f94a2cf6c8e0f 100644
--- a/src/xpdev/ini_file.h
+++ b/src/xpdev/ini_file.h
@@ -48,6 +48,13 @@ typedef struct {
 	const char*	name;
 } ini_bitdesc_t;
 
+typedef struct {
+	int			key_len;
+	const char* key_prefix;
+	const char* value_separator;
+	const char*	bit_separator;
+} ini_style_t;
+
 #if defined(__cplusplus)
 extern "C" {
 #endif
@@ -90,6 +97,24 @@ void*		iniFreeNamedStringList(named_string_t** list);
 str_list_t	iniReadFile(FILE* fp);
 BOOL		iniWriteFile(FILE* fp, const str_list_t list);
 
+/* StringList functions */
+size_t		iniAddSection(str_list_t* list, const char* section);
+char*		iniSetString(str_list_t* list, const char* section, const char* key, const char* value
+					,ini_style_t*);
+char*		iniSetInteger(str_list_t* list, const char* section, const char* key, long value
+					,ini_style_t*);
+char*		iniSetShortInt(str_list_t* list, const char* section, const char* key, ushort value
+					,ini_style_t*);
+char*		iniSetHexInt(str_list_t* list, const char* section, const char* key, ulong value
+					,ini_style_t*);
+char*		iniSetFloat(str_list_t* list, const char* section, const char* key, double value
+					,ini_style_t*);
+char*		iniSetIpAddress(str_list_t* list, const char* section, const char* key, ulong value
+					,ini_style_t*);
+char*		iniSetBool(str_list_t* list, const char* section, const char* key, BOOL value
+					,ini_style_t*);
+char*		iniSetBitField(str_list_t* list, const char* section, const char* key, ulong value
+					,ini_bitdesc_t*, ini_style_t*);
 
 #if defined(__cplusplus)
 }