make config parser a bit more careful about quotes
the parsing is more shell-like now: - quoted and unquoted parts can be mixed in one argument - the hashmark can be meaningfully quoted
This commit is contained in:
		
							parent
							
								
									2e07e68630
								
							
						
					
					
						commit
						725a122e91
					
				
					 4 changed files with 85 additions and 50 deletions
				
			
		
							
								
								
									
										70
									
								
								src/config.c
									
										
									
									
									
								
							
							
						
						
									
										70
									
								
								src/config.c
									
										
									
									
									
								
							| 
						 | 
					@ -22,10 +22,12 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "isync.h"
 | 
					#include "isync.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <limits.h>
 | 
					#include <limits.h>
 | 
				
			||||||
#include <pwd.h>
 | 
					#include <pwd.h>
 | 
				
			||||||
#include <sys/types.h>
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#include <ctype.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
| 
						 | 
					@ -38,6 +40,46 @@ group_conf_t *groups;
 | 
				
			||||||
int global_ops[2];
 | 
					int global_ops[2];
 | 
				
			||||||
char *global_sync_state;
 | 
					char *global_sync_state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ARG_OPTIONAL 0
 | 
				
			||||||
 | 
					#define ARG_REQUIRED 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char *
 | 
				
			||||||
 | 
					get_arg( conffile_t *cfile, int required, int *comment )
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *ret, *p, *t;
 | 
				
			||||||
 | 
						int quoted;
 | 
				
			||||||
 | 
						char c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						p = cfile->rest;
 | 
				
			||||||
 | 
						assert( p );
 | 
				
			||||||
 | 
						while ((c = *p) && isspace( (unsigned char) c ))
 | 
				
			||||||
 | 
							p++;
 | 
				
			||||||
 | 
						if (!c || c == '#') {
 | 
				
			||||||
 | 
							if (comment)
 | 
				
			||||||
 | 
								*comment = (c == '#');
 | 
				
			||||||
 | 
							if (required)
 | 
				
			||||||
 | 
								error( "%s:%d: parameter missing\n", cfile->file, cfile->line );
 | 
				
			||||||
 | 
							ret = 0;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							for (quoted = 0, ret = t = p; c; c = *p) {
 | 
				
			||||||
 | 
								p++;
 | 
				
			||||||
 | 
								if (c == '"')
 | 
				
			||||||
 | 
									quoted ^= 1;
 | 
				
			||||||
 | 
								else if (!quoted && isspace( (unsigned char) c ))
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									*t++ = c;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							*t = 0;
 | 
				
			||||||
 | 
							if (quoted) {
 | 
				
			||||||
 | 
								error( "%s:%d: missing closing quote\n", cfile->file, cfile->line );
 | 
				
			||||||
 | 
								ret = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						cfile->rest = p;
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
parse_bool( conffile_t *cfile )
 | 
					parse_bool( conffile_t *cfile )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -132,7 +174,7 @@ getopt_helper( conffile_t *cfile, int *cops, int ops[], char **sync_state )
 | 
				
			||||||
			else if (strcasecmp( "None", arg ) && strcasecmp( "Noop", arg ))
 | 
								else if (strcasecmp( "None", arg ) && strcasecmp( "Noop", arg ))
 | 
				
			||||||
				error( "%s:%d: invalid Sync arg '%s'\n",
 | 
									error( "%s:%d: invalid Sync arg '%s'\n",
 | 
				
			||||||
				       cfile->file, cfile->line, arg );
 | 
									       cfile->file, cfile->line, arg );
 | 
				
			||||||
		while ((arg = next_arg( &cfile->rest )));
 | 
							while ((arg = get_arg( cfile, ARG_OPTIONAL, 0 )));
 | 
				
			||||||
		ops[M] |= XOP_HAVE_TYPE;
 | 
							ops[M] |= XOP_HAVE_TYPE;
 | 
				
			||||||
	} else if (!strcasecmp( "Expunge", cfile->cmd )) {
 | 
						} else if (!strcasecmp( "Expunge", cfile->cmd )) {
 | 
				
			||||||
		arg = cfile->val;
 | 
							arg = cfile->val;
 | 
				
			||||||
| 
						 | 
					@ -146,7 +188,7 @@ getopt_helper( conffile_t *cfile, int *cops, int ops[], char **sync_state )
 | 
				
			||||||
			else if (strcasecmp( "None", arg ))
 | 
								else if (strcasecmp( "None", arg ))
 | 
				
			||||||
				error( "%s:%d: invalid Expunge arg '%s'\n",
 | 
									error( "%s:%d: invalid Expunge arg '%s'\n",
 | 
				
			||||||
				       cfile->file, cfile->line, arg );
 | 
									       cfile->file, cfile->line, arg );
 | 
				
			||||||
		while ((arg = next_arg( &cfile->rest )));
 | 
							while ((arg = get_arg( cfile, ARG_OPTIONAL, 0 )));
 | 
				
			||||||
		ops[M] |= XOP_HAVE_EXPUNGE;
 | 
							ops[M] |= XOP_HAVE_EXPUNGE;
 | 
				
			||||||
	} else if (!strcasecmp( "Create", cfile->cmd )) {
 | 
						} else if (!strcasecmp( "Create", cfile->cmd )) {
 | 
				
			||||||
		arg = cfile->val;
 | 
							arg = cfile->val;
 | 
				
			||||||
| 
						 | 
					@ -160,7 +202,7 @@ getopt_helper( conffile_t *cfile, int *cops, int ops[], char **sync_state )
 | 
				
			||||||
			else if (strcasecmp( "None", arg ))
 | 
								else if (strcasecmp( "None", arg ))
 | 
				
			||||||
				error( "%s:%d: invalid Create arg '%s'\n",
 | 
									error( "%s:%d: invalid Create arg '%s'\n",
 | 
				
			||||||
				       cfile->file, cfile->line, arg );
 | 
									       cfile->file, cfile->line, arg );
 | 
				
			||||||
		while ((arg = next_arg( &cfile->rest )));
 | 
							while ((arg = get_arg( cfile, ARG_OPTIONAL, 0 )));
 | 
				
			||||||
		ops[M] |= XOP_HAVE_CREATE;
 | 
							ops[M] |= XOP_HAVE_CREATE;
 | 
				
			||||||
	} else if (!strcasecmp( "SyncState", cfile->cmd ))
 | 
						} else if (!strcasecmp( "SyncState", cfile->cmd ))
 | 
				
			||||||
		*sync_state = expand_strdup( cfile->val );
 | 
							*sync_state = expand_strdup( cfile->val );
 | 
				
			||||||
| 
						 | 
					@ -172,20 +214,18 @@ getopt_helper( conffile_t *cfile, int *cops, int ops[], char **sync_state )
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
getcline( conffile_t *cfile )
 | 
					getcline( conffile_t *cfile )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char *p;
 | 
						int comment;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (fgets( cfile->buf, cfile->bufl, cfile->fp )) {
 | 
						while (fgets( cfile->buf, cfile->bufl, cfile->fp )) {
 | 
				
			||||||
		cfile->line++;
 | 
							cfile->line++;
 | 
				
			||||||
		p = cfile->buf;
 | 
							cfile->rest = cfile->buf;
 | 
				
			||||||
		if (!(cfile->cmd = next_arg( &p )))
 | 
							if (!(cfile->cmd = get_arg( cfile, ARG_OPTIONAL, &comment ))) {
 | 
				
			||||||
 | 
								if (comment)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
			return 1;
 | 
								return 1;
 | 
				
			||||||
		if (*cfile->cmd == '#')
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		if (!(cfile->val = next_arg( &p ))) {
 | 
					 | 
				
			||||||
			error( "%s:%d: parameter missing\n", cfile->file, cfile->line );
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		cfile->rest = p;
 | 
							if (!(cfile->val = get_arg( cfile, ARG_REQUIRED, 0 )))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -311,7 +351,7 @@ load_config( const char *where, int pseudo )
 | 
				
			||||||
					arg = cfile.val;
 | 
										arg = cfile.val;
 | 
				
			||||||
					do
 | 
										do
 | 
				
			||||||
						add_string_list( &channel->patterns, arg );
 | 
											add_string_list( &channel->patterns, arg );
 | 
				
			||||||
					while ((arg = next_arg( &cfile.rest )));
 | 
										while ((arg = get_arg( &cfile, ARG_OPTIONAL, 0 )));
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				else if (!strcasecmp( "Master", cfile.cmd )) {
 | 
									else if (!strcasecmp( "Master", cfile.cmd )) {
 | 
				
			||||||
					ms = M;
 | 
										ms = M;
 | 
				
			||||||
| 
						 | 
					@ -367,8 +407,7 @@ load_config( const char *where, int pseudo )
 | 
				
			||||||
			*groupapp = 0;
 | 
								*groupapp = 0;
 | 
				
			||||||
			chanlistapp = &group->channels;
 | 
								chanlistapp = &group->channels;
 | 
				
			||||||
			*chanlistapp = 0;
 | 
								*chanlistapp = 0;
 | 
				
			||||||
			p = cfile.rest;
 | 
								while ((arg = get_arg( &cfile, ARG_OPTIONAL, 0 ))) {
 | 
				
			||||||
			while ((arg = next_arg( &p ))) {
 | 
					 | 
				
			||||||
			  addone:
 | 
								  addone:
 | 
				
			||||||
				len = strlen( arg );
 | 
									len = strlen( arg );
 | 
				
			||||||
				chanlist = nfmalloc( sizeof(*chanlist) + len );
 | 
									chanlist = nfmalloc( sizeof(*chanlist) + len );
 | 
				
			||||||
| 
						 | 
					@ -383,7 +422,6 @@ load_config( const char *where, int pseudo )
 | 
				
			||||||
				if (!strcasecmp( "Channel", cfile.cmd ) ||
 | 
									if (!strcasecmp( "Channel", cfile.cmd ) ||
 | 
				
			||||||
				    !strcasecmp( "Channels", cfile.cmd ))
 | 
									    !strcasecmp( "Channels", cfile.cmd ))
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					p = cfile.rest;
 | 
					 | 
				
			||||||
					arg = cfile.val;
 | 
										arg = cfile.val;
 | 
				
			||||||
					goto addone;
 | 
										goto addone;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -450,6 +450,37 @@ imap_refcounted_done_box( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, i
 | 
				
			||||||
	imap_refcounted_done( sts );
 | 
						imap_refcounted_done( sts );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char *
 | 
				
			||||||
 | 
					next_arg( char **s )
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!s || !*s)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						while (isspace( (unsigned char) **s ))
 | 
				
			||||||
 | 
							(*s)++;
 | 
				
			||||||
 | 
						if (!**s) {
 | 
				
			||||||
 | 
							*s = 0;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (**s == '"') {
 | 
				
			||||||
 | 
							++*s;
 | 
				
			||||||
 | 
							ret = *s;
 | 
				
			||||||
 | 
							*s = strchr( *s, '"' );
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ret = *s;
 | 
				
			||||||
 | 
							while (**s && !isspace( (unsigned char) **s ))
 | 
				
			||||||
 | 
								(*s)++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (*s) {
 | 
				
			||||||
 | 
							if (**s)
 | 
				
			||||||
 | 
								*(*s)++ = 0;
 | 
				
			||||||
 | 
							if (!**s)
 | 
				
			||||||
 | 
								*s = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
is_atom( list_t *list )
 | 
					is_atom( list_t *list )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -412,8 +412,6 @@ void ATTR_PRINTFLIKE(1, 2) error( const char *, ... );
 | 
				
			||||||
void ATTR_PRINTFLIKE(1, 2) sys_error( const char *, ... );
 | 
					void ATTR_PRINTFLIKE(1, 2) sys_error( const char *, ... );
 | 
				
			||||||
void flushn( void );
 | 
					void flushn( void );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char *next_arg( char ** );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void add_string_list( string_list_t **list, const char *str );
 | 
					void add_string_list( string_list_t **list, const char *str );
 | 
				
			||||||
void free_string_list( string_list_t *list );
 | 
					void free_string_list( string_list_t *list );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										32
									
								
								src/util.c
									
										
									
									
									
								
							
							
						
						
									
										32
									
								
								src/util.c
									
										
									
									
									
								
							| 
						 | 
					@ -28,7 +28,6 @@
 | 
				
			||||||
#include <fcntl.h>
 | 
					#include <fcntl.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <pwd.h>
 | 
					#include <pwd.h>
 | 
				
			||||||
#include <ctype.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
int DFlags;
 | 
					int DFlags;
 | 
				
			||||||
static int need_nl;
 | 
					static int need_nl;
 | 
				
			||||||
| 
						 | 
					@ -145,37 +144,6 @@ sys_error( const char *msg, ... )
 | 
				
			||||||
	perror( buf );
 | 
						perror( buf );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char *
 | 
					 | 
				
			||||||
next_arg( char **s )
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	char *ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!s || !*s)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	while (isspace( (unsigned char) **s ))
 | 
					 | 
				
			||||||
		(*s)++;
 | 
					 | 
				
			||||||
	if (!**s) {
 | 
					 | 
				
			||||||
		*s = 0;
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (**s == '"') {
 | 
					 | 
				
			||||||
		++*s;
 | 
					 | 
				
			||||||
		ret = *s;
 | 
					 | 
				
			||||||
		*s = strchr( *s, '"' );
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		ret = *s;
 | 
					 | 
				
			||||||
		while (**s && !isspace( (unsigned char) **s ))
 | 
					 | 
				
			||||||
			(*s)++;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (*s) {
 | 
					 | 
				
			||||||
		if (**s)
 | 
					 | 
				
			||||||
			*(*s)++ = 0;
 | 
					 | 
				
			||||||
		if (!**s)
 | 
					 | 
				
			||||||
			*s = 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
add_string_list( string_list_t **list, const char *str )
 | 
					add_string_list( string_list_t **list, const char *str )
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue