Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
607d1643
Commit
607d1643
authored
Jun 15, 2011
by
Vicent Martí
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #248 from carlosmn/config
Implement config writing
parents
536955f9
a98b0d80
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
231 additions
and
7 deletions
+231
-7
src/config_file.c
+207
-7
tests/resources/config/config9
+2
-0
tests/t15-config.c
+22
-0
No files found.
src/config_file.c
View file @
607d1643
...
...
@@ -26,9 +26,11 @@
#include "common.h"
#include "config.h"
#include "fileops.h"
#include "filebuf.h"
#include "git2/config.h"
#include "git2/types.h"
#include <ctype.h>
typedef
struct
cvar_t
{
...
...
@@ -98,6 +100,7 @@ typedef struct {
static
int
config_parse
(
diskfile_backend
*
cfg_file
);
static
int
parse_variable
(
diskfile_backend
*
cfg
,
char
**
var_name
,
char
**
var_value
);
static
int
config_write
(
diskfile_backend
*
cfg
,
cvar_t
*
var
);
static
void
cvar_free
(
cvar_t
*
var
)
{
...
...
@@ -130,7 +133,7 @@ static void cvar_list_free(cvar_t_list *list)
*/
static
int
cvar_match_section
(
const
char
*
local
,
const
char
*
input
)
{
char
*
first_dot
,
*
last_dot
;
char
*
first_dot
;
char
*
local_sp
=
strchr
(
local
,
' '
);
int
comparison_len
;
...
...
@@ -159,12 +162,8 @@ static int cvar_match_section(const char *local, const char *input)
*/
first_dot
=
strchr
(
input
,
'.'
);
last_dot
=
strrchr
(
input
,
'.'
);
comparison_len
=
strlen
(
local_sp
+
2
)
-
1
;
if
(
last_dot
==
first_dot
||
last_dot
-
first_dot
-
1
!=
comparison_len
)
return
0
;
return
!
strncmp
(
local_sp
+
2
,
first_dot
+
1
,
comparison_len
);
}
...
...
@@ -241,6 +240,39 @@ static int cvar_normalize_name(cvar_t *var, char **output)
return
GIT_SUCCESS
;
}
static
char
*
interiorize_section
(
const
char
*
orig
)
{
char
*
dot
,
*
last_dot
,
*
section
,
*
ret
;
int
len
;
dot
=
strchr
(
orig
,
'.'
);
last_dot
=
strrchr
(
orig
,
'.'
);
len
=
last_dot
-
orig
;
/* No subsection, this is easy */
if
(
last_dot
==
dot
)
return
git__strndup
(
orig
,
dot
-
orig
);
section
=
git__malloc
(
len
+
4
);
if
(
section
==
NULL
)
return
NULL
;
memset
(
section
,
0x0
,
len
+
4
);
ret
=
section
;
len
=
dot
-
orig
;
memcpy
(
section
,
orig
,
len
);
section
+=
len
;
len
=
STRLEN
(
"
\"
"
);
memcpy
(
section
,
"
\"
"
,
len
);
section
+=
len
;
len
=
last_dot
-
dot
-
1
;
memcpy
(
section
,
dot
+
1
,
len
);
section
+=
len
;
*
section
=
'"'
;
return
ret
;
}
static
int
config_open
(
git_config_file
*
cfg
)
{
int
error
;
...
...
@@ -320,7 +352,7 @@ static int config_set(git_config_file *cfg, const char *name, const char *value)
free
(
existing
->
value
);
existing
->
value
=
tmp
;
return
GIT_SUCCESS
;
return
config_write
(
b
,
existing
)
;
}
/*
...
...
@@ -338,7 +370,7 @@ static int config_set(git_config_file *cfg, const char *name, const char *value)
memset
(
var
,
0x0
,
sizeof
(
cvar_t
));
var
->
section
=
git__strndup
(
name
,
last_dot
-
name
);
var
->
section
=
interiorize_section
(
name
);
if
(
var
->
section
==
NULL
)
{
error
=
GIT_ENOMEM
;
goto
out
;
...
...
@@ -357,6 +389,7 @@ static int config_set(git_config_file *cfg, const char *name, const char *value)
}
CVAR_LIST_APPEND
(
&
b
->
var_list
,
var
);
error
=
config_write
(
b
,
var
);
out:
if
(
error
<
GIT_SUCCESS
)
...
...
@@ -863,6 +896,173 @@ static int config_parse(diskfile_backend *cfg_file)
return
error
==
GIT_SUCCESS
?
GIT_SUCCESS
:
git__rethrow
(
error
,
"Failed to parse config"
);
}
static
int
write_section
(
git_filebuf
*
file
,
cvar_t
*
var
)
{
int
error
;
error
=
git_filebuf_printf
(
file
,
"[%s]
\n
"
,
var
->
section
);
if
(
error
<
GIT_SUCCESS
)
return
error
;
error
=
git_filebuf_printf
(
file
,
" %s = %s
\n
"
,
var
->
name
,
var
->
value
);
return
error
;
}
/*
* This is pretty much the parsing, except we write out anything we don't have
*/
static
int
config_write
(
diskfile_backend
*
cfg
,
cvar_t
*
var
)
{
int
error
=
GIT_SUCCESS
,
c
;
int
section_matches
=
0
,
last_section_matched
=
0
;
char
*
current_section
=
NULL
;
char
*
var_name
,
*
var_value
,
*
data_start
;
git_filebuf
file
;
const
char
*
pre_end
=
NULL
,
*
post_start
=
NULL
;
/* We need to read in our own config file */
error
=
gitfo_read_file
(
&
cfg
->
reader
.
buffer
,
cfg
->
file_path
);
if
(
error
<
GIT_SUCCESS
)
{
return
git__rethrow
(
error
,
"Failed to read existing config file %s"
,
cfg
->
file_path
);
}
/* Initialise the reading position */
cfg
->
reader
.
read_ptr
=
cfg
->
reader
.
buffer
.
data
;
cfg
->
reader
.
eof
=
0
;
data_start
=
cfg
->
reader
.
read_ptr
;
/* Lock the file */
error
=
git_filebuf_open
(
&
file
,
cfg
->
file_path
,
0
);
if
(
error
<
GIT_SUCCESS
)
return
git__rethrow
(
error
,
"Failed to lock config file"
);
skip_bom
(
cfg
);
while
(
error
==
GIT_SUCCESS
&&
!
cfg
->
reader
.
eof
)
{
c
=
cfg_peek
(
cfg
,
SKIP_WHITESPACE
);
switch
(
c
)
{
case
'\0'
:
/* We've arrived at the end of the file */
break
;
case
'['
:
/* section header, new section begins */
/*
* We set both positions to the current one in case we
* need to add a variable to the end of a section. In that
* case, we want both variables to point just before the
* new section. If we actually want to replace it, the
* default case will take care of updating them.
*/
pre_end
=
post_start
=
cfg
->
reader
.
read_ptr
;
free
(
current_section
);
error
=
parse_section_header
(
cfg
,
&
current_section
);
if
(
error
<
GIT_SUCCESS
)
break
;
/* Keep track of when it stops matching */
last_section_matched
=
section_matches
;
section_matches
=
!
strcmp
(
current_section
,
var
->
section
);
break
;
case
';'
:
case
'#'
:
cfg_consume_line
(
cfg
);
break
;
default
:
/*
* If the section doesn't match, but the last section did,
* it means we need to add a variable (so skip the line
* otherwise). If both the section and name match, we need
* to overwrite the variable (so skip the line
* otherwise). pre_end needs to be updated each time so we
* don't loose that information, but we only need to
* update post_start if we're going to use it in this
* iteration.
*/
if
(
!
section_matches
)
{
if
(
!
last_section_matched
)
{
cfg_consume_line
(
cfg
);
break
;
}
}
else
{
pre_end
=
cfg
->
reader
.
read_ptr
;
error
=
parse_variable
(
cfg
,
&
var_name
,
&
var_value
);
if
(
error
<
GIT_SUCCESS
||
strcasecmp
(
var
->
name
,
var_name
))
break
;
post_start
=
cfg
->
reader
.
read_ptr
;
}
/*
* We've found the variable we wanted to change, so
* write anything up to it
*/
error
=
git_filebuf_write
(
&
file
,
data_start
,
pre_end
-
data_start
);
if
(
error
<
GIT_SUCCESS
)
{
git__rethrow
(
error
,
"Failed to write the first part of the file"
);
break
;
}
/* Then replace the variable */
error
=
git_filebuf_printf
(
&
file
,
"
\t
%s = %s
\n
"
,
var
->
name
,
var
->
value
);
if
(
error
<
GIT_SUCCESS
)
{
git__rethrow
(
error
,
"Failed to overwrite the variable"
);
break
;
}
/* And then the write out rest of the file */
error
=
git_filebuf_write
(
&
file
,
post_start
,
cfg
->
reader
.
buffer
.
len
-
(
post_start
-
data_start
));
if
(
error
<
GIT_SUCCESS
)
{
git__rethrow
(
error
,
"Failed to write the rest of the file"
);
break
;
}
goto
cleanup
;
}
}
/*
* Being here can mean that
*
* 1) our section is the last one in the file and we're
* adding a variable
*
* 2) we didn't find a section for us so we need to create it
* ourselves.
*
* Either way we need to write out the whole file.
*/
error
=
git_filebuf_write
(
&
file
,
cfg
->
reader
.
buffer
.
data
,
cfg
->
reader
.
buffer
.
len
);
if
(
error
<
GIT_SUCCESS
)
{
git__rethrow
(
error
,
"Failed to write original config content"
);
goto
cleanup
;
}
/* And now if we just need to add a variable */
if
(
section_matches
)
{
error
=
git_filebuf_printf
(
&
file
,
"
\t
%s = %s
\n
"
,
var
->
name
,
var
->
value
);
goto
cleanup
;
}
/* Or maybe we need to write out a whole section */
error
=
write_section
(
&
file
,
var
);
if
(
error
<
GIT_SUCCESS
)
git__rethrow
(
error
,
"Failed to write new section"
);
cleanup
:
free
(
current_section
);
if
(
error
<
GIT_SUCCESS
)
git_filebuf_cleanup
(
&
file
);
else
error
=
git_filebuf_commit
(
&
file
);
return
error
;
}
static
int
is_multiline_var
(
const
char
*
str
)
{
char
*
end
=
strrchr
(
str
,
'\0'
)
-
1
;
...
...
tests/resources/config/config9
0 → 100644
View file @
607d1643
[core]
dummy = 1
tests/t15-config.c
View file @
607d1643
...
...
@@ -189,6 +189,27 @@ BEGIN_TEST(config8, "don't fail on empty files")
git_config_free
(
cfg
);
END_TEST
BEGIN_TEST
(
config9
,
"replace a value"
)
git_config
*
cfg
;
int
i
;
/* By freeing the config, we make sure we flush the values */
must_pass
(
git_config_open_file
(
&
cfg
,
CONFIG_BASE
"/config9"
));
must_pass
(
git_config_set_int
(
cfg
,
"core.dummy"
,
5
));
git_config_free
(
cfg
);
must_pass
(
git_config_open_file
(
&
cfg
,
CONFIG_BASE
"/config9"
));
must_pass
(
git_config_get_int
(
cfg
,
"core.dummy"
,
&
i
));
must_be_true
(
i
==
5
);
git_config_free
(
cfg
);
must_pass
(
git_config_open_file
(
&
cfg
,
CONFIG_BASE
"/config9"
));
must_pass
(
git_config_set_int
(
cfg
,
"core.dummy"
,
1
));
git_config_free
(
cfg
);
END_TEST
BEGIN_SUITE
(
config
)
ADD_TEST
(
config0
);
ADD_TEST
(
config1
);
...
...
@@ -199,4 +220,5 @@ BEGIN_SUITE(config)
ADD_TEST
(
config6
);
ADD_TEST
(
config7
);
ADD_TEST
(
config8
);
ADD_TEST
(
config9
);
END_SUITE
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment