Toggle navigation
Toggle navigation
This project
Loading...
Sign in
UT
/
clsync
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
redmine
2014-06-09 21:49:53 +0400
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
e67df67d19dd16dddfe1325c5580e1101a837b8d
e67df67d
1 parent
28389aeb
rsyncdirect: Added support of custom arguments
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
344 additions
and
61 deletions
Makefile.am
common.h
ctx.h
main.c
main.h
malloc.c
man/man1/clsync.1
stringex.c
stringex.h
sync.c
Makefile.am
View file @
e67df67
...
...
@@ -5,8 +5,9 @@ if CLSYNC
bin_PROGRAMS
=
clsync
clsync_SOURCES
=
calc.c cluster.c error.c fileutils.c glibex.c
\
indexes.c main.c malloc.c sync.c calc.h cluster.h fileutils.h
\
glibex.h main.h port-hacks.h sync.h common.h control.h
indexes.c main.c malloc.c stringex.c sync.c calc.h cluster.h
\
fileutils.h glibex.h main.h port-hacks.h stringex.h sync.h
\
common.h control.h
clsync_CFLAGS
=
$(AM_CFLAGS)
...
...
common.h
View file @
e67df67
...
...
@@ -187,29 +187,35 @@ struct eventinfo {
};
typedef
struct
eventinfo
eventinfo_t
;
struct
thread_callbackfunct_arg
{
char
*
excfpath
;
char
*
incfpath
;
};
typedef
struct
thread_callbackfunct_arg
thread_callbackfunct_arg_t
;
typedef
int
(
*
thread_callbackfunct_t
)(
ctx_t
*
ctx_p
,
char
**
argv
);
typedef
int
(
*
thread_callbackfunct_t
)(
ctx_t
*
ctx_p
,
thread_callbackfunct_arg_t
*
arg_p
);
struct
threadinfo
{
int
thread_num
;
uint32_t
iteration
;
thread_callbackfunct_t
callback
;
char
**
argv
;
pthread_t
pthread
;
int
exitcode
;
int
errcode
;
state_t
state
;
ctx_t
*
ctx_p
;
time_t
starttime
;
time_t
expiretime
;
int
child_pid
;
GHashTable
*
fpath2ei_ht
;
// file path -> event information
int
try_n
;
int
thread_num
;
uint32_t
iteration
;
thread_callbackfunct_t
callback
;
thread_callbackfunct_arg_t
*
callback_arg
;
char
**
argv
;
pthread_t
pthread
;
int
exitcode
;
int
errcode
;
state_t
state
;
ctx_t
*
ctx_p
;
time_t
starttime
;
time_t
expiretime
;
int
child_pid
;
GHashTable
*
fpath2ei_ht
;
// file path -> event information
int
try_n
;
// for so-synchandler
int
n
;
api_eventinfo_t
*
ei
;
int
n
;
api_eventinfo_t
*
ei
;
};
typedef
struct
threadinfo
threadinfo_t
;
...
...
ctx.h
View file @
e67df67
...
...
@@ -98,6 +98,8 @@ enum flags_enum {
CONFIGBLOCKINHERITS
=
18
|
OPTION_LONGOPTONLY
,
MONITOR
=
19
|
OPTION_LONGOPTONLY
,
SYNCHANDLERARGS
=
20
|
OPTION_LONGOPTONLY
,
};
typedef
enum
flags_enum
flags_t
;
...
...
@@ -242,6 +244,9 @@ struct ctx {
#endif
void
*
indexes_p
;
void
*
fsmondata
;
char
*
synchandler_argv
[
MAXARGUMENTS
];
int
synchandler_argc
;
};
typedef
struct
ctx
ctx_t
;
...
...
main.c
View file @
e67df67
/*
clsync - file tree sync utility based on inotify
clsync - file tree sync utility based on inotify
/kqueue/bsm
Copyright (C) 201
3
Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
Copyright (C) 201
4
Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
...
...
@@ -26,6 +26,7 @@
#include <grp.h> // For getgrnam()
#include "error.h"
#include "stringex.h"
#include "sync.h"
#include "malloc.h"
#include "cluster.h"
...
...
@@ -38,6 +39,7 @@ static const struct option long_options[] =
{
{
"watch-dir"
,
required_argument
,
NULL
,
WATCHDIR
},
{
"sync-handler"
,
required_argument
,
NULL
,
SYNCHANDLER
},
{
"--"
,
required_argument
,
NULL
,
SYNCHANDLERARGS
},
{
"rules-file"
,
required_argument
,
NULL
,
RULESFILE
},
{
"destination-dir"
,
required_argument
,
NULL
,
DESTDIR
},
{
"mode"
,
required_argument
,
NULL
,
MODE
},
...
...
@@ -191,7 +193,8 @@ int clsyncapi_getapiversion() {
* @retval NULL On error
*
*/
char
*
parameter_get
(
ctx_t
*
ctx_p
,
char
*
variable_name
)
{
char
*
parameter_get
(
char
*
variable_name
,
void
*
_ctx_p
)
{
ctx_t
*
ctx_p
=
_ctx_p
;
const
struct
option
*
long_option_p
=
long_options
;
int
param_id
=
-
1
;
...
...
@@ -222,7 +225,8 @@ char *parameter_get(ctx_t *ctx_p, char *variable_name) {
* @retval NULL On error
*
*/
char
*
parameter_expand
(
ctx_t
*
ctx_p
,
char
*
arg
,
int
ignorewarnings
)
{
char
*
parameter_expand
(
ctx_t
*
ctx_p
,
char
*
arg
,
int
exceptionflags
,
char
*
(
*
parameter_get
)(
char
*
variable_name
,
void
*
arg
),
void
*
parameter_get_arg
)
{
debug
(
9
,
""
);
char
*
ret
=
NULL
;
size_t
ret_size
=
0
,
ret_len
=
0
;
...
...
@@ -239,8 +243,12 @@ char *parameter_expand(ctx_t *ctx_p, char *arg, int ignorewarnings) {
switch
(
*
ptr
)
{
case
0
:
if
(
ret
==
NULL
)
{
debug
(
3
,
"Expanding value
\"
%s
\"
to
\"
%s
\"
(case #1)"
,
arg
,
arg
);
return
arg
;
}
ret
[
ret_len
]
=
0
;
debug
(
3
,
"Expanding value
\"
%s
\"
to
\"
%s
\"
"
,
arg
,
ret
);
debug
(
3
,
"Expanding value
\"
%s
\"
to
\"
%s
\"
(case #0)
"
,
arg
,
ret
);
free
(
arg
);
return
ret
;
case
'%'
:
{
...
...
@@ -257,24 +265,33 @@ char *parameter_expand(ctx_t *ctx_p, char *arg, int ignorewarnings) {
switch
(
*
ptr_nest
)
{
case
0
:
ret
[
ret_len
]
=
0
;
if
(
!
(
ignorewarnin
gs
&
1
))
warning
(
"Unexpected end of macro-substitution
\"
%
%%s
\"
in value
\"
%s
\"
; result value is
\"
%s
\"
"
,
ptr_nest
,
arg
,
ret
);
if
(
!
(
exceptionfla
gs
&
1
))
warning
(
"Unexpected end of macro-substitution
\"
%
s
\"
in value
\"
%s
\"
; result value is
\"
%s
\"
"
,
ptr
,
arg
,
ret
);
free
(
arg
);
return
ret
;
case
'%'
:
{
char
*
variable_name
;
char
*
variable_value
;
size_t
variable_value_len
;
nest_searching
=
0
;
*
ptr_nest
=
0
;
char
*
variable_name
=
&
ptr
[
1
];
char
*
variable_value
=
parameter_get
(
ctx_p
,
variable_name
);
if
(
variable_value
==
NULL
)
{
if
(
!
(
ignorewarnings
&
2
))
warning
(
"Variable
\"
%s
\"
is not set (%s)"
,
variable_name
,
strerror
(
errno
));
if
(
ptr
[
1
]
>=
'A'
&&
ptr
[
1
]
<=
'Z'
&&
(
exceptionflags
&
4
))
{
// Lazy substitution, preserving the value
variable_value
=
ptr
;
variable_value_len
=
(
ptr_nest
-
ptr
+
1
);
}
else
{
// Substituting
*
ptr_nest
=
0
;
variable_name
=
&
ptr
[
1
];
variable_value
=
parameter_get
(
variable_name
,
parameter_get_arg
);
if
(
variable_value
==
NULL
)
{
if
(
!
(
exceptionflags
&
2
))
warning
(
"Variable
\"
%s
\"
is not set (%s)"
,
variable_name
,
strerror
(
errno
));
*
ptr_nest
=
'%'
;
errno
=
0
;
break
;
}
*
ptr_nest
=
'%'
;
errno
=
0
;
break
;
variable_value_len
=
strlen
(
variable_value
);
}
*
ptr_nest
=
'%'
;
size_t
variable_value_len
=
strlen
(
variable_value
);
if
(
ret_len
+
variable_value_len
+
1
>=
ret_size
)
{
ret_size
=
ret_len
+
variable_value_len
+
1
+
ALLOC_PORTION
;
ret
=
xrealloc
(
ret
,
ret_size
);
...
...
@@ -302,6 +319,22 @@ char *parameter_expand(ctx_t *ctx_p, char *arg, int ignorewarnings) {
return
arg
;
}
static
int
synchandler_arg
(
char
*
arg
,
size_t
arg_len
,
void
*
_ctx_p
)
{
ctx_t
*
ctx_p
=
_ctx_p
;
debug
(
9
,
"(
\"
%s
\"
, %u, %p)"
,
arg
,
arg_len
,
_ctx_p
);
if
(
ctx_p
->
synchandler_argc
>=
MAXARGUMENTS
-
2
)
{
errno
=
E2BIG
;
error
(
"There're too many sync-handler arguments "
"(%u > "
XTOSTR
(
MAXARGUMENTS
-
2
)
"; arg ==
\"
%s
\"
)."
,
arg
);
return
errno
;
}
ctx_p
->
synchandler_argv
[
ctx_p
->
synchandler_argc
++
]
=
arg
;
return
0
;
}
int
parse_parameter
(
ctx_t
*
ctx_p
,
uint16_t
param_id
,
char
*
arg
,
paramsource_t
paramsource
)
{
#ifdef _DEBUG
fprintf
(
stderr
,
"Force-Debug: parse_parameter(): %i: %i =
\"
%s
\"\n
"
,
paramsource
,
param_id
,
arg
);
...
...
@@ -325,7 +358,8 @@ int parse_parameter(ctx_t *ctx_p, uint16_t param_id, char *arg, paramsource_t pa
}
if
(
arg
!=
NULL
)
{
arg
=
parameter_expand
(
ctx_p
,
arg
,
0
);
if
(
param_id
!=
SYNCHANDLERARGS
)
arg
=
parameter_expand
(
ctx_p
,
arg
,
0
,
parameter_get
,
ctx_p
);
if
(
ctx_p
->
flags_values_raw
[
param_id
]
!=
NULL
)
free
(
ctx_p
->
flags_values_raw
[
param_id
]);
...
...
@@ -660,6 +694,9 @@ int parse_parameter(ctx_t *ctx_p, uint16_t param_id, char *arg, paramsource_t pa
}
break
;
}
case
SYNCHANDLERARGS
:
str_splitargs
(
arg
,
synchandler_arg
,
ctx_p
);
break
;
default:
if
(
arg
==
NULL
)
ctx_p
->
flags
[
param_id
]
++
;
...
...
@@ -682,7 +719,7 @@ int arguments_parse(int argc, char *argv[], struct ctx *ctx_p) {
char
*
optstring_ptr
=
optstring
;
const
struct
option
*
lo_ptr
=
long_options
;
while
(
lo_ptr
->
name
!=
NULL
)
{
while
(
lo_ptr
->
name
!=
NULL
)
{
if
(
!
(
lo_ptr
->
val
&
(
OPTION_CONFIGONLY
|
OPTION_LONGOPTONLY
)))
{
*
(
optstring_ptr
++
)
=
lo_ptr
->
val
&
0xff
;
...
...
@@ -702,20 +739,31 @@ int arguments_parse(int argc, char *argv[], struct ctx *ctx_p) {
#endif
// Parsing arguments
while
(
1
)
{
while
(
1
)
{
c
=
getopt_long
(
argc
,
argv
,
optstring
,
long_options
,
&
option_index
);
if
(
c
==
-
1
)
break
;
int
ret
=
parse_parameter
(
ctx_p
,
c
,
optarg
==
NULL
?
NULL
:
strdup
(
optarg
),
PS_ARGUMENT
);
if
(
ret
)
return
ret
;
if
(
ret
)
return
ret
;
}
if
(
optind
<
argc
)
{
while
(
ctx_p
->
synchandler_argc
)
free
(
ctx_p
->
synchandler_argv
[
--
ctx_p
->
synchandler_argc
]);
if
((
optind
+
1
!=
argc
)
||
(
*
argv
[
optind
]))
{
// If there's only "" after the "--", just reset "synchandler_argc" to "0", otherwise:
do
{
if
(
synchandler_arg
(
argv
[
optind
++
],
0
,
ctx_p
))
return
errno
;
}
while
(
optind
<
argc
);
}
}
if
(
optind
+
1
<
argc
)
syntax
();
return
0
;
}
void
gkf_parse
(
ctx_t
*
ctx_p
,
GKeyFile
*
gkf
)
{
debug
(
9
,
""
);
char
*
config_block
=
ctx_p
->
config_block
;
do
{
const
struct
option
*
lo_ptr
=
long_options
;
...
...
@@ -758,7 +806,7 @@ int configs_parse(ctx_t *ctx_p) {
return
0
;
}
debug
(
1
,
"Trying config-file
\"
%s
\"
"
,
ctx_p
->
config_path
);
debug
(
1
,
"Trying config-file
\"
%s
\"
(case #0)
"
,
ctx_p
->
config_path
);
if
(
!
g_key_file_load_from_file
(
gkf
,
ctx_p
->
config_path
,
G_KEY_FILE_NONE
,
&
g_error
))
{
error
(
"Cannot open/parse file
\"
%s
\"
(g_error #%u.%u: %s)"
,
ctx_p
->
config_path
,
g_error
->
domain
,
g_error
->
code
,
g_error
->
message
);
g_key_file_free
(
gkf
);
...
...
@@ -789,7 +837,7 @@ int configs_parse(ctx_t *ctx_p) {
}
else
memcpy
(
config_path_real
,
*
config_path_p
,
config_path_len
+
1
);
debug
(
1
,
"Trying config-file
\"
%s
\"
"
,
config_path_real
);
debug
(
1
,
"Trying config-file
\"
%s
\"
(case #1)
"
,
config_path_real
);
if
(
!
g_key_file_load_from_file
(
gkf
,
config_path_real
,
G_KEY_FILE_NONE
,
NULL
))
{
debug
(
1
,
"Cannot open/parse file
\"
%s
\"
"
,
config_path_real
);
config_path_p
++
;
...
...
@@ -819,6 +867,18 @@ void options_cleanup(ctx_t *ctx_p) {
i
++
;
}
#if 0
{
int i = 0;
while (i < ctx_p->synchandler_argc) {
// TODO: FIXME: Here's a double "free":
free(ctx_p->synchandler_argv[i]);
ctx_p->synchandler_argv[i] = NULL;
i++;
}
ctx_p->synchandler_argc = 0;
}
#endif
return
;
}
...
...
@@ -1205,10 +1265,18 @@ int main(int argc, char *argv[]) {
}
if
(
ctx_p
->
dump_path
==
NULL
)
{
ctx_p
->
dump_path
=
parameter_expand
(
ctx_p
,
strdup
(
DEFAULT_DUMPDIR
),
2
);
ctx_p
->
dump_path
=
parameter_expand
(
ctx_p
,
strdup
(
DEFAULT_DUMPDIR
),
2
,
parameter_get
,
ctx_p
);
ctx_p
->
flags_values_raw
[
DUMPDIR
]
=
ctx_p
->
dump_path
;
}
{
int
i
=
0
;
while
(
i
<
ctx_p
->
synchandler_argc
)
{
ctx_p
->
synchandler_argv
[
i
]
=
parameter_expand
(
ctx_p
,
strdup
(
ctx_p
->
synchandler_argv
[
i
]),
4
,
parameter_get
,
ctx_p
);
i
++
;
}
}
debug
(
4
,
"debugging flags: %u %u %u %u"
,
ctx_p
->
flags
[
OUTPUT_METHOD
],
ctx_p
->
flags
[
QUIET
],
ctx_p
->
flags
[
VERBOSE
],
ctx_p
->
flags
[
DEBUG
]);
main_status_update
(
ctx_p
,
STATE_STARTING
);
...
...
main.h
View file @
e67df67
...
...
@@ -19,4 +19,5 @@
extern
int
main_rehash
(
ctx_t
*
ctx_p
);
extern
int
main_status_update
(
ctx_t
*
ctx_p
,
state_t
state
);
extern
char
*
parameter_expand
(
ctx_t
*
ctx_p
,
char
*
arg
,
int
ignorewarnings
,
char
*
(
*
parameter_get
)(
char
*
variable_name
,
void
*
arg
),
void
*
parameter_get_arg
);
...
...
malloc.c
View file @
e67df67
...
...
@@ -24,6 +24,9 @@
#include "error.h"
void
*
xmalloc
(
size_t
size
)
{
#ifdef _DEBUG
debug
(
20
,
"(%u)"
,
size
);
#endif
#ifdef PARANOID
size
++
;
// Just in case
#endif
...
...
@@ -40,6 +43,9 @@ void *xmalloc(size_t size) {
}
void
*
xcalloc
(
size_t
nmemb
,
size_t
size
)
{
#ifdef _DEBUG
debug
(
20
,
"(%u, %u)"
,
nmemb
,
size
);
#endif
#ifdef PARANOID
nmemb
++
;
// Just in case
size
++
;
// Just in case
...
...
@@ -55,6 +61,9 @@ void *xcalloc(size_t nmemb, size_t size) {
}
void
*
xrealloc
(
void
*
oldptr
,
size_t
size
)
{
#ifdef _DEBUG
debug
(
20
,
"(%p, %u)"
,
oldptr
,
size
);
#endif
#ifdef PARANOID
size
++
;
// Just in case
#endif
...
...
man/man1/clsync.1
View file @
e67df67
...
...
@@ -7,7 +7,7 @@
.SH NAME
clsync \- live sync tool, written in GNU C
.SH SYNOPSIS
.B clsync [ ... ]
.B clsync [ ... ]
-- [ sync\-handler\-arguments ]
.SH DESCRIPTION
.B clsync
executes
...
...
@@ -106,8 +106,7 @@ calls
.IR rsyncdirect
.RS
calls rsync by path
.IR sync\-handler " directly (inflexible and unreliable, should be used only
as a proof of concept)"
.IR sync\-handler " directly"
.RE
.IR rsyncshell
.RS
...
...
@@ -1045,26 +1044,50 @@ case
.RS
Executes for every sync:
.br
.I sync\-handler
\-\-inplace \-aH \-\-delete\-before [\-\-exclude\-from
.I rsync\-exclude\-listpath
]
\-\-include\-from
.I rsync\-listpath
\-\-exclude '*'
.I watch-dir/ dest-dir/
.I sync\-handler sync\-handler\-arguments
In this case,
.I sync\-handler
is supposed to be a path to
.B rsync
binary.
Default value for
.I sync\-handler\-arguments
is
.RS
\-aH \-\-delete \-\-exclude\-from %EXCLUDE\-LIST% \-\-include\-from
%INCLUDE-LIST% --exclude='*' %watch-dir%/ %destination-dir%/
.RE
if option
.I \-\-rsync-\-prefer\-include
is not set and
.RS
\-aH \-\-delete \-\-include\-from %INCLUDE-LIST% --exclude='*' %watch-dir%/
%destination-dir%/
.RE
if the option is set
Error code "24" from
.I sync\-handler
will be ignored in this case.
This case is supposed to be used only as a proof of concept.
Additional substitutions:
.RS
%INCLUDE-LIST%
.RS
Is replaced by path to include list file
.RE
%EXCLUDE-LIST%
.RS
Is replaced by path to exclude list file
.RE
.RE
Recommended case.
.RE
case
...
...
@@ -1135,7 +1158,7 @@ be able to kill the child.
See example file "clsync-synchandler-rsyncso.c".
Recommended case.
IMHO, this way is the best.
Recommended case.
.RE
case
...
...
stringex.c
0 → 100644
View file @
e67df67
/*
clsync - file tree sync utility based on inotify/kqueue/bsm
Copyright (C) 2014 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h> // free()
#include <string.h> // strtok_r()
#include <errno.h> // errno
#include "malloc.h"
#include "error.h"
static
int
_str_splitargs
(
char
*
ptr
,
char
**
arg_start_p
,
int
quotes
,
int
(
*
handler
)(
char
*
,
size_t
,
void
*
),
char
*
additional_arg
)
{
char
*
arg_start
,
*
arg
;
size_t
arg_len
;
int
rc
;
arg_start
=
*
arg_start_p
;
*
arg_start_p
=
&
ptr
[
1
];
arg_len
=
ptr
-
arg_start
;
if
(
arg_len
==
0
)
// Skipping nearby spaces
return
0
;
arg
=
xmalloc
(
arg_len
+
1
);
if
(
quotes
)
{
int
s
,
d
;
s
=
d
=
0
;
while
(
s
<
arg_len
)
{
if
(
arg_start
[
s
])
arg
[
d
++
]
=
arg_start
[
s
];
s
++
;
}
arg_len
=
d
;
}
else
memcpy
(
arg
,
arg_start
,
arg_len
);
#ifdef _DEBUG
debug
(
15
,
"%p %p %i: <%s>"
,
arg_start
,
ptr
,
arg_len
,
arg
);
#endif
arg
[
arg_len
]
=
0
;
if
((
rc
=
handler
(
arg
,
arg_len
,
additional_arg
)))
{
free
(
arg
);
return
rc
;
}
return
0
;
}
int
str_splitargs
(
char
*
instr
,
int
(
*
handler
)(
char
*
,
size_t
,
void
*
),
void
*
arg
)
{
debug
(
9
,
""
);
char
*
arg_start
,
*
ptr
;
int
quotes
=
0
;
ptr
=
instr
;
arg_start
=
instr
;
while
(
1
)
{
ptr
=
strpbrk
(
ptr
,
"
\t\"\'
"
);
#ifdef _DEBUG
debug
(
10
,
"ptr == %p"
,
ptr
);
#endif
if
(
ptr
==
NULL
)
break
;
#ifdef _DEBUG
debug
(
10
,
"*ptr ==
\"
%c
\"
(%i)"
,
*
ptr
,
*
ptr
);
#endif
switch
(
*
(
ptr
++
))
{
case
' '
:
case
'\t'
:
{
int
rc
;
if
((
rc
=
_str_splitargs
(
&
ptr
[
-
1
],
&
arg_start
,
quotes
,
handler
,
arg
)))
return
rc
;
quotes
=
0
;
break
;
}
case
'"'
:
ptr
[
-
1
]
=
0
;
quotes
++
;
while
((
ptr
=
strchr
(
ptr
,
'"'
))
!=
NULL
)
{
// Checking for escaping
char
*
p
;
p
=
&
ptr
[
-
1
];
while
(
*
p
==
'\\'
)
{
p
--
;
#ifdef PARANOID
if
(
p
<
instr
)
critical
(
"Dangerous internal error"
);
#endif
}
if
((
ptr
-
p
)
%
2
)
break
;
}
if
(
ptr
==
NULL
)
{
errno
=
EINVAL
;
error
(
"Unterminated quote <
\"
> in string: <%s>"
,
instr
);
return
errno
;
}
*
ptr
=
0
;
quotes
++
;
ptr
++
;
break
;
case
'\''
:
ptr
[
-
1
]
=
0
;
quotes
++
;
ptr
=
strchr
(
ptr
,
'\''
);
if
(
ptr
==
NULL
)
{
errno
=
EINVAL
;
error
(
"Unterminated quote <'> in string: <%s>"
,
instr
);
return
errno
;
}
*
ptr
=
0
;
quotes
++
;
ptr
++
;
break
;
}
}
return
_str_splitargs
(
strchr
(
arg_start
,
0
),
&
arg_start
,
quotes
,
handler
,
arg
);
}
...
...
stringex.h
0 → 100644
View file @
e67df67
/*
clsync - file tree sync utility based on inotify/kqueue/bsm
Copyright (C) 2014 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
extern
int
str_splitargs
(
const
char
*
const
instr
,
int
(
*
handler
)(
char
*
outstr
,
size_t
outstr_len
,
void
*
arg
),
void
*
arg
);
...
...
sync.c
View file @
e67df67
This diff is collapsed. Click to expand it.
Please
register
or
login
to post a comment