1
1
use std:: ffi:: { c_void, CStr , CString } ;
2
- use std:: path:: Path ;
2
+ use std:: path:: { Path , PathBuf } ;
3
3
4
4
#[ cfg( has_std__ffi__c_char) ]
5
- use std:: ffi:: { c_char, c_int} ;
5
+ use std:: ffi:: { c_char, c_int, c_ulong } ;
6
6
7
7
#[ cfg( not( has_std__ffi__c_char) ) ]
8
8
#[ allow( non_camel_case_types) ]
@@ -12,6 +12,10 @@ type c_char = i8;
12
12
#[ allow( non_camel_case_types) ]
13
13
type c_int = i32 ;
14
14
15
+ #[ cfg( not( has_std__ffi__c_char) ) ]
16
+ #[ allow( non_camel_case_types) ]
17
+ type c_ulong = u64 ;
18
+
15
19
use libgit_sys:: * ;
16
20
17
21
/// A ConfigSet is an in-memory cache for config-like files such as `.gitmodules` or `.gitconfig`.
@@ -68,6 +72,55 @@ impl ConfigSet {
68
72
Some ( owned_str)
69
73
}
70
74
}
75
+
76
+ /// Load the value for the given key and attempt to parse it as a boolean. Dies with a fatal error
77
+ /// if the value cannot be parsed. Returns None if the key is not present.
78
+ pub fn get_bool ( & mut self , key : & str ) -> Option < bool > {
79
+ let key = CString :: new ( key) . expect ( "config key should be valid CString" ) ;
80
+ let mut val: c_int = 0 ;
81
+ unsafe {
82
+ if libgit_configset_get_bool ( self . 0 , key. as_ptr ( ) , & mut val as * mut c_int ) != 0 {
83
+ return None ;
84
+ }
85
+ }
86
+
87
+ Some ( val != 0 )
88
+ }
89
+
90
+ /// Load the value for the given key and attempt to parse it as an unsigned long. Dies with a fatal error
91
+ /// if the value cannot be parsed. Returns None if the key is not present.
92
+ pub fn get_ulong ( & mut self , key : & str ) -> Option < u64 > {
93
+ let key = CString :: new ( key) . expect ( "config key should be valid CString" ) ;
94
+ let mut val: c_ulong = 0 ;
95
+ unsafe {
96
+ if libgit_configset_get_ulong ( self . 0 , key. as_ptr ( ) , & mut val as * mut c_ulong ) != 0 {
97
+ return None ;
98
+ }
99
+ }
100
+ Some ( val as u64 )
101
+ }
102
+
103
+ /// Load the value for the given key and attempt to parse it as a file path. Dies with a fatal error
104
+ /// if the value cannot be converted to a PathBuf. Returns None if the key is not present.
105
+ pub fn get_pathname ( & mut self , key : & str ) -> Option < PathBuf > {
106
+ let key = CString :: new ( key) . expect ( "config key should be valid CString" ) ;
107
+ let mut val: * mut c_char = std:: ptr:: null_mut ( ) ;
108
+ unsafe {
109
+ if libgit_configset_get_pathname ( self . 0 , key. as_ptr ( ) , & mut val as * mut * mut c_char )
110
+ != 0
111
+ {
112
+ return None ;
113
+ }
114
+ let borrowed_str = CStr :: from_ptr ( val) ;
115
+ let owned_str = String :: from (
116
+ borrowed_str
117
+ . to_str ( )
118
+ . expect ( "config path should be valid UTF-8" ) ,
119
+ ) ;
120
+ free ( val as * mut c_void ) ; // Free the xstrdup()ed pointer from the C side
121
+ Some ( PathBuf :: from ( owned_str) )
122
+ }
123
+ }
71
124
}
72
125
73
126
impl Default for ConfigSet {
@@ -95,12 +148,38 @@ mod tests {
95
148
Path :: new ( "testdata/config1" ) ,
96
149
Path :: new ( "testdata/config2" ) ,
97
150
Path :: new ( "testdata/config3" ) ,
151
+ Path :: new ( "testdata/config4" ) ,
98
152
] ) ;
99
153
// ConfigSet retrieves correct value
100
154
assert_eq ! ( cs. get_int( "trace2.eventTarget" ) , Some ( 1 ) ) ;
101
155
// ConfigSet respects last config value set
102
156
assert_eq ! ( cs. get_int( "trace2.eventNesting" ) , Some ( 3 ) ) ;
103
157
// ConfigSet returns None for missing key
104
158
assert_eq ! ( cs. get_string( "foo.bar" ) , None ) ;
159
+ // Test boolean parsing - comprehensive tests
160
+ assert_eq ! ( cs. get_bool( "test.boolTrue" ) , Some ( true ) ) ;
161
+ assert_eq ! ( cs. get_bool( "test.boolFalse" ) , Some ( false ) ) ;
162
+ assert_eq ! ( cs. get_bool( "test.boolYes" ) , Some ( true ) ) ;
163
+ assert_eq ! ( cs. get_bool( "test.boolNo" ) , Some ( false ) ) ;
164
+ assert_eq ! ( cs. get_bool( "test.boolOne" ) , Some ( true ) ) ;
165
+ assert_eq ! ( cs. get_bool( "test.boolZero" ) , Some ( false ) ) ;
166
+ assert_eq ! ( cs. get_bool( "test.boolZeroZero" ) , Some ( false ) ) ; // "00" → false
167
+ assert_eq ! ( cs. get_bool( "test.boolHundred" ) , Some ( true ) ) ; // "100" → true
168
+ // Test missing boolean key
169
+ assert_eq ! ( cs. get_bool( "missing.boolean" ) , None ) ;
170
+ // Test ulong parsing
171
+ assert_eq ! ( cs. get_ulong( "test.ulongSmall" ) , Some ( 42 ) ) ;
172
+ assert_eq ! ( cs. get_ulong( "test.ulongBig" ) , Some ( 4294967296 ) ) ; // > 32-bit int
173
+ assert_eq ! ( cs. get_ulong( "missing.ulong" ) , None ) ;
174
+ // Test pathname parsing
175
+ assert_eq ! (
176
+ cs. get_pathname( "test.pathRelative" ) ,
177
+ Some ( PathBuf :: from( "./some/path" ) )
178
+ ) ;
179
+ assert_eq ! (
180
+ cs. get_pathname( "test.pathAbsolute" ) ,
181
+ Some ( PathBuf :: from( "/usr/bin/git" ) )
182
+ ) ;
183
+ assert_eq ! ( cs. get_pathname( "missing.path" ) , None ) ;
105
184
}
106
185
}
0 commit comments