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
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…
Reference in New Issue
Block a user