]>
git.proxmox.com Git - libgit2.git/blob - src/config_file.c
2 * Copyright (C) 2009-2012 the libgit2 contributors
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
13 #include "git2/config.h"
14 #include "git2/types.h"
19 typedef struct cvar_t
{
21 char *key
; /* TODO: we might be able to get rid of this */
30 #define CVAR_LIST_HEAD(list) ((list)->head)
32 #define CVAR_LIST_TAIL(list) ((list)->tail)
34 #define CVAR_LIST_NEXT(var) ((var)->next)
36 #define CVAR_LIST_EMPTY(list) ((list)->head == NULL)
38 #define CVAR_LIST_APPEND(list, var) do {\
39 if (CVAR_LIST_EMPTY(list)) {\
40 CVAR_LIST_HEAD(list) = CVAR_LIST_TAIL(list) = var;\
42 CVAR_LIST_NEXT(CVAR_LIST_TAIL(list)) = var;\
43 CVAR_LIST_TAIL(list) = var;\
47 #define CVAR_LIST_REMOVE_HEAD(list) do {\
48 CVAR_LIST_HEAD(list) = CVAR_LIST_NEXT(CVAR_LIST_HEAD(list));\
51 #define CVAR_LIST_REMOVE_AFTER(var) do {\
52 CVAR_LIST_NEXT(var) = CVAR_LIST_NEXT(CVAR_LIST_NEXT(var));\
55 #define CVAR_LIST_FOREACH(list, iter)\
56 for ((iter) = CVAR_LIST_HEAD(list);\
58 (iter) = CVAR_LIST_NEXT(iter))
61 * Inspired by the FreeBSD functions
63 #define CVAR_LIST_FOREACH_SAFE(start, iter, tmp)\
64 for ((iter) = CVAR_LIST_HEAD(vars);\
65 (iter) && (((tmp) = CVAR_LIST_NEXT(iter) || 1));\
69 git_config_file parent
;
71 git_hashtable
*values
;
83 static int config_parse(diskfile_backend
*cfg_file
);
84 static int parse_variable(diskfile_backend
*cfg
, char **var_name
, char **var_value
);
85 static int config_write(diskfile_backend
*cfg
, const char *key
, const char *value
);
87 static void cvar_free(cvar_t
*var
)
93 git__free(var
->value
);
97 /* Take something the user gave us and make it nice for our hash function */
98 static int normalize_name(const char *in
, char **out
)
100 char *name
, *fdot
, *ldot
;
104 name
= git__strdup(in
);
108 fdot
= strchr(name
, '.');
109 ldot
= strrchr(name
, '.');
111 if (fdot
== NULL
|| ldot
== NULL
) {
113 return git__throw(GIT_EINVALIDARGS
, "Bad format. No dot in '%s'", in
);
116 /* Downcase up to the first dot and after the last one */
117 git__strntolower(name
, fdot
- name
);
118 git__strtolower(ldot
);
124 static void free_vars(git_hashtable
*values
)
126 const char *GIT_UNUSED(_unused
) = NULL
;
132 GIT_HASHTABLE_FOREACH(values
, _unused
, var
,
134 cvar_t
*next
= CVAR_LIST_NEXT(var
);
137 } while (var
!= NULL
);
140 git_hashtable_free(values
);
143 static int config_open(git_config_file
*cfg
)
146 diskfile_backend
*b
= (diskfile_backend
*)cfg
;
148 b
->values
= git_hashtable_alloc (20, git_hash__strhash_cb
, git_hash__strcmp_cb
);
149 if (b
->values
== NULL
)
152 error
= git_futils_readbuffer(&b
->reader
.buffer
, b
->file_path
);
154 /* It's fine if the file doesn't exist */
155 if (error
== GIT_ENOTFOUND
)
158 if (error
< GIT_SUCCESS
)
161 error
= config_parse(b
);
162 if (error
< GIT_SUCCESS
)
165 git_futils_freebuffer(&b
->reader
.buffer
);
170 free_vars(b
->values
);
172 git_futils_freebuffer(&b
->reader
.buffer
);
174 return git__rethrow(error
, "Failed to open config");
177 static void backend_free(git_config_file
*_backend
)
179 diskfile_backend
*backend
= (diskfile_backend
*)_backend
;
184 git__free(backend
->file_path
);
186 free_vars(backend
->values
);
191 static int file_foreach(git_config_file
*backend
, int (*fn
)(const char *, const char *, void *), void *data
)
193 int ret
= GIT_SUCCESS
;
195 diskfile_backend
*b
= (diskfile_backend
*)backend
;
198 GIT_HASHTABLE_FOREACH(b
->values
, key
, var
,
200 ret
= fn(key
, var
->value
, data
);
203 var
= CVAR_LIST_NEXT(var
);
204 } while (var
!= NULL
);
211 static int config_set(git_config_file
*cfg
, const char *name
, const char *value
)
214 cvar_t
*existing
= NULL
, *old_value
= NULL
;
215 int error
= GIT_SUCCESS
;
216 diskfile_backend
*b
= (diskfile_backend
*)cfg
;
219 if ((error
= normalize_name(name
, &key
)) < GIT_SUCCESS
)
220 return git__rethrow(error
, "Failed to normalize variable name '%s'", name
);
223 * Try to find it in the existing values and update it if it
224 * only has one value.
226 existing
= git_hashtable_lookup(b
->values
, key
);
227 if (existing
!= NULL
) {
231 if (existing
->next
!= NULL
)
232 return git__throw(GIT_EINVALIDARGS
, "Multivar incompatible with simple set");
234 tmp
= value
? git__strdup(value
) : NULL
;
235 if (tmp
== NULL
&& value
!= NULL
)
238 git__free(existing
->value
);
239 existing
->value
= tmp
;
241 return config_write(b
, existing
->key
, value
);
244 var
= git__malloc(sizeof(cvar_t
));
248 memset(var
, 0x0, sizeof(cvar_t
));
252 var
->value
= value
? git__strdup(value
) : NULL
;
253 if (var
->value
== NULL
&& value
!= NULL
) {
258 error
= git_hashtable_insert2(b
->values
, key
, var
, (void **)&old_value
);
259 if (error
< GIT_SUCCESS
)
262 cvar_free(old_value
);
264 error
= config_write(b
, key
, value
);
267 if (error
< GIT_SUCCESS
)
270 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to set config value");
274 * Internal function that actually gets the value in string form
276 static int config_get(git_config_file
*cfg
, const char *name
, const char **out
)
279 int error
= GIT_SUCCESS
;
280 diskfile_backend
*b
= (diskfile_backend
*)cfg
;
283 if ((error
= normalize_name(name
, &key
)) < GIT_SUCCESS
)
286 var
= git_hashtable_lookup(b
->values
, key
);
290 return git__throw(GIT_ENOTFOUND
, "Variable '%s' not found", name
);
294 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to get config value for %s", name
);
297 static int config_delete(git_config_file
*cfg
, const char *name
)
302 diskfile_backend
*b
= (diskfile_backend
*)cfg
;
305 if ((error
= normalize_name(name
, &key
)) < GIT_SUCCESS
)
308 var
= git_hashtable_lookup(b
->values
, key
);
312 return git__throw(GIT_ENOTFOUND
, "Variable '%s' not found", name
);
314 if (var
->next
!= NULL
)
315 return git__throw(GIT_EINVALIDARGS
, "Multivar incompatible with simple delete");
318 if ((error
= git_hashtable_remove2(b
->values
, var
->key
, (void **)&old_value
)) < GIT_SUCCESS
)
319 return git__rethrow(error
, "Failed to remove %s from hashtable", key
);
321 error
= config_write(b
, var
->key
, NULL
);
322 cvar_free(old_value
);
327 int git_config_file__ondisk(git_config_file
**out
, const char *path
)
329 diskfile_backend
*backend
;
331 backend
= git__malloc(sizeof(diskfile_backend
));
335 memset(backend
, 0x0, sizeof(diskfile_backend
));
337 backend
->file_path
= git__strdup(path
);
338 if (backend
->file_path
== NULL
) {
343 backend
->parent
.open
= config_open
;
344 backend
->parent
.get
= config_get
;
345 backend
->parent
.set
= config_set
;
346 backend
->parent
.del
= config_delete
;
347 backend
->parent
.foreach
= file_foreach
;
348 backend
->parent
.free
= backend_free
;
350 *out
= (git_config_file
*)backend
;
355 static int cfg_getchar_raw(diskfile_backend
*cfg
)
359 c
= *cfg
->reader
.read_ptr
++;
362 Win 32 line breaks: if we find a \r\n sequence,
363 return only the \n as a newline
365 if (c
== '\r' && *cfg
->reader
.read_ptr
== '\n') {
366 cfg
->reader
.read_ptr
++;
371 cfg
->reader
.line_number
++;
381 #define SKIP_WHITESPACE (1 << 1)
382 #define SKIP_COMMENTS (1 << 2)
384 static int cfg_getchar(diskfile_backend
*cfg_file
, int flags
)
386 const int skip_whitespace
= (flags
& SKIP_WHITESPACE
);
387 const int skip_comments
= (flags
& SKIP_COMMENTS
);
390 assert(cfg_file
->reader
.read_ptr
);
392 do c
= cfg_getchar_raw(cfg_file
);
393 while (skip_whitespace
&& isspace(c
) &&
394 !cfg_file
->reader
.eof
);
396 if (skip_comments
&& (c
== '#' || c
== ';')) {
397 do c
= cfg_getchar_raw(cfg_file
);
405 * Read the next char, but don't move the reading pointer.
407 static int cfg_peek(diskfile_backend
*cfg
, int flags
)
410 int old_lineno
, old_eof
;
413 assert(cfg
->reader
.read_ptr
);
415 old_read_ptr
= cfg
->reader
.read_ptr
;
416 old_lineno
= cfg
->reader
.line_number
;
417 old_eof
= cfg
->reader
.eof
;
419 ret
= cfg_getchar(cfg
, flags
);
421 cfg
->reader
.read_ptr
= old_read_ptr
;
422 cfg
->reader
.line_number
= old_lineno
;
423 cfg
->reader
.eof
= old_eof
;
429 * Read and consume a line, returning it in newly-allocated memory.
431 static char *cfg_readline(diskfile_backend
*cfg
)
434 char *line_src
, *line_end
;
437 line_src
= cfg
->reader
.read_ptr
;
439 /* Skip empty empty lines */
440 while (isspace(*line_src
))
443 line_end
= strchr(line_src
, '\n');
445 /* no newline at EOF */
446 if (line_end
== NULL
)
447 line_end
= strchr(line_src
, 0);
449 line_len
= line_end
- line_src
;
451 line
= git__malloc(line_len
+ 1);
455 memcpy(line
, line_src
, line_len
);
457 do line
[line_len
] = '\0';
458 while (line_len
-- > 0 && isspace(line
[line_len
]));
460 if (*line_end
== '\n')
463 if (*line_end
== '\0')
466 cfg
->reader
.line_number
++;
467 cfg
->reader
.read_ptr
= line_end
;
473 * Consume a line, without storing it anywhere
475 static void cfg_consume_line(diskfile_backend
*cfg
)
477 char *line_start
, *line_end
;
479 line_start
= cfg
->reader
.read_ptr
;
480 line_end
= strchr(line_start
, '\n');
481 /* No newline at EOF */
482 if(line_end
== NULL
){
483 line_end
= strchr(line_start
, '\0');
486 if (*line_end
== '\n')
489 if (*line_end
== '\0')
492 cfg
->reader
.line_number
++;
493 cfg
->reader
.read_ptr
= line_end
;
496 GIT_INLINE(int) config_keychar(int c
)
498 return isalnum(c
) || c
== '-';
501 static int parse_section_header_ext(const char *line
, const char *base_name
, char **section_name
)
504 char *first_quote
, *last_quote
;
505 git_buf buf
= GIT_BUF_INIT
;
506 int error
= GIT_SUCCESS
;
509 * base_name is what came before the space. We should be at the
510 * first quotation mark, except for now, line isn't being kept in
511 * sync so we only really use it to calculate the length.
514 first_quote
= strchr(line
, '"');
515 last_quote
= strrchr(line
, '"');
517 if (last_quote
- first_quote
== 0)
518 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse ext header. There is no final quotation mark");
520 git_buf_grow(&buf
, strlen(base_name
) + last_quote
- first_quote
+ 2);
521 git_buf_printf(&buf
, "%s.", base_name
);
530 * At the end of each iteration, whatever is stored in c will be
531 * added to the string. In case of error, jump to out
534 if (quote_marks
== 2) {
535 puts("too many marks");
536 error
= git__throw(GIT_EOBJCORRUPTED
, "Falied to parse ext header. Text after closing quote");
552 error
= git__throw(GIT_EOBJCORRUPTED
, "Failed to parse ext header. Unsupported escape char \\%c", c
);
560 git_buf_putc(&buf
, c
);
561 } while ((c
= line
[rpos
++]) != ']');
563 *section_name
= git__strdup(git_buf_cstr(&buf
));
570 static int parse_section_header(diskfile_backend
*cfg
, char **section_out
)
572 char *name
, *name_end
;
573 int name_length
, c
, pos
;
574 int error
= GIT_SUCCESS
;
577 line
= cfg_readline(cfg
);
581 /* find the end of the variable's name */
582 name_end
= strchr(line
, ']');
583 if (name_end
== NULL
) {
585 return git__throw(GIT_EOBJCORRUPTED
, "Failed to parse header. Can't find header name end");
588 name
= (char *)git__malloc((size_t)(name_end
- line
) + 1);
597 /* Make sure we were given a section header */
600 error
= git__throw(GIT_ERROR
, "Failed to parse header. Didn't get section header. This is a bug");
608 name
[name_length
] = '\0';
609 error
= parse_section_header_ext(line
, name
, section_out
);
612 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to parse header");
615 if (!config_keychar(c
) && c
!= '.') {
616 error
= git__throw(GIT_EOBJCORRUPTED
, "Failed to parse header. Wrong format on header");
620 name
[name_length
++] = (char) tolower(c
);
622 } while ((c
= line
[pos
++]) != ']');
624 if (line
[pos
- 1] != ']') {
625 error
= git__throw(GIT_EOBJCORRUPTED
, "Failed to parse header. Config file ended unexpectedly");
629 name
[name_length
] = 0;
631 git__strtolower(name
);
641 static int skip_bom(diskfile_backend
*cfg
)
643 static const char utf8_bom
[] = "\xef\xbb\xbf";
645 if (cfg
->reader
.buffer
.len
< sizeof(utf8_bom
))
648 if (memcmp(cfg
->reader
.read_ptr
, utf8_bom
, sizeof(utf8_bom
)) == 0)
649 cfg
->reader
.read_ptr
+= sizeof(utf8_bom
);
651 /* TODO: the reference implementation does pretty stupid
661 integer = digit { digit }
662 alphabet = "a".."z" + "A" .. "Z"
664 section_char = alphabet | "." | "-"
665 extension_char = (* any character except newline *)
666 any_char = (* any character *)
667 variable_char = "alphabet" | "-"
673 section = header { definition }
675 header = "[" section [subsection | subsection_ext] "]"
677 subsection = "." section
678 subsection_ext = "\"" extension "\""
680 section = section_char { section_char }
681 extension = extension_char { extension_char }
683 definition = variable_name ["=" variable_value] "\n"
685 variable_name = variable_char { variable_char }
686 variable_value = string | boolean | integer
688 string = quoted_string | plain_string
689 quoted_string = "\"" plain_string "\""
690 plain_string = { any_char }
692 boolean = boolean_true | boolean_false
693 boolean_true = "yes" | "1" | "true" | "on"
694 boolean_false = "no" | "0" | "false" | "off"
697 static void strip_comments(char *line
)
702 for (ptr
= line
; *ptr
; ++ptr
) {
703 if (ptr
[0] == '"' && ptr
> line
&& ptr
[-1] != '\\')
706 if ((ptr
[0] == ';' || ptr
[0] == '#') && (quote_count
% 2) == 0) {
712 if (isspace(ptr
[-1])) {
713 /* TODO skip whitespace */
717 static int config_parse(diskfile_backend
*cfg_file
)
719 int error
= GIT_SUCCESS
, c
;
720 char *current_section
= NULL
;
724 git_buf buf
= GIT_BUF_INIT
;
726 /* Initialize the reading position */
727 cfg_file
->reader
.read_ptr
= cfg_file
->reader
.buffer
.data
;
728 cfg_file
->reader
.eof
= 0;
730 /* If the file is empty, there's nothing for us to do */
731 if (*cfg_file
->reader
.read_ptr
== '\0')
736 while (error
== GIT_SUCCESS
&& !cfg_file
->reader
.eof
) {
738 c
= cfg_peek(cfg_file
, SKIP_WHITESPACE
);
741 case '\n': /* EOF when peeking, set EOF in the reader to exit the loop */
742 cfg_file
->reader
.eof
= 1;
745 case '[': /* section header, new section begins */
746 git__free(current_section
);
747 current_section
= NULL
;
748 error
= parse_section_header(cfg_file
, ¤t_section
);
753 cfg_consume_line(cfg_file
);
756 default: /* assume variable declaration */
757 error
= parse_variable(cfg_file
, &var_name
, &var_value
);
759 if (error
< GIT_SUCCESS
)
762 var
= git__malloc(sizeof(cvar_t
));
768 memset(var
, 0x0, sizeof(cvar_t
));
770 git__strtolower(var_name
);
771 git_buf_printf(&buf
, "%s.%s", current_section
, var_name
);
774 if (git_buf_oom(&buf
)) {
779 var
->key
= git_buf_detach(&buf
);
780 var
->value
= var_value
;
782 /* FIXME: Actually support multivars, don't just overwrite */
783 error
= git_hashtable_insert(cfg_file
->values
, var
->key
, var
);
789 git__free(current_section
);
791 return error
== GIT_SUCCESS
? GIT_SUCCESS
: git__rethrow(error
, "Failed to parse config");
794 static int write_section(git_filebuf
*file
, const char *key
)
797 const char *fdot
, *ldot
;
798 git_buf buf
= GIT_BUF_INIT
;
800 /* All of this just for [section "subsection"] */
801 fdot
= strchr(key
, '.');
802 git_buf_putc(&buf
, '[');
804 git_buf_puts(&buf
, key
);
806 git_buf_put(&buf
, key
, fdot
- key
);
807 ldot
= strrchr(key
, '.');
808 if (fdot
!= ldot
&& fdot
!= NULL
) {
809 git_buf_putc(&buf
, '"');
811 git_buf_put(&buf
, fdot
+ 1, ldot
- fdot
- 1);
812 git_buf_putc(&buf
, '"');
814 git_buf_puts(&buf
, "]\n");
815 if (git_buf_oom(&buf
))
818 error
= git_filebuf_write(file
, git_buf_cstr(&buf
), buf
.size
);
825 * This is pretty much the parsing, except we write out anything we don't have
827 static int config_write(diskfile_backend
*cfg
, const char *key
, const char* value
)
829 int error
= GIT_SUCCESS
, c
;
830 int section_matches
= 0, last_section_matched
= 0;
831 char *current_section
= NULL
, *section
, *name
, *ldot
;
832 char *var_name
, *var_value
, *data_start
;
833 git_filebuf file
= GIT_FILEBUF_INIT
;
834 const char *pre_end
= NULL
, *post_start
= NULL
;
836 /* We need to read in our own config file */
837 error
= git_futils_readbuffer(&cfg
->reader
.buffer
, cfg
->file_path
);
838 if (error
< GIT_SUCCESS
&& error
!= GIT_ENOTFOUND
) {
839 return git__rethrow(error
, "Failed to read existing config file %s", cfg
->file_path
);
842 /* Initialise the reading position */
843 if (error
== GIT_ENOTFOUND
) {
845 cfg
->reader
.read_ptr
= NULL
;
848 cfg
->reader
.buffer
.len
= 0;
849 cfg
->reader
.buffer
.data
= NULL
;
851 cfg
->reader
.read_ptr
= cfg
->reader
.buffer
.data
;
853 data_start
= cfg
->reader
.read_ptr
;
857 error
= git_filebuf_open(&file
, cfg
->file_path
, 0);
858 if (error
< GIT_SUCCESS
)
859 return git__rethrow(error
, "Failed to lock config file");
862 ldot
= strrchr(key
, '.');
864 section
= git__strndup(key
, ldot
- key
);
866 while (error
== GIT_SUCCESS
&& !cfg
->reader
.eof
) {
867 c
= cfg_peek(cfg
, SKIP_WHITESPACE
);
870 case '\0': /* We've arrived at the end of the file */
873 case '[': /* section header, new section begins */
875 * We set both positions to the current one in case we
876 * need to add a variable to the end of a section. In that
877 * case, we want both variables to point just before the
878 * new section. If we actually want to replace it, the
879 * default case will take care of updating them.
881 pre_end
= post_start
= cfg
->reader
.read_ptr
;
883 git__free(current_section
);
884 error
= parse_section_header(cfg
, ¤t_section
);
885 if (error
< GIT_SUCCESS
)
888 /* Keep track of when it stops matching */
889 last_section_matched
= section_matches
;
890 section_matches
= !strcmp(current_section
, section
);
895 cfg_consume_line(cfg
);
900 * If the section doesn't match, but the last section did,
901 * it means we need to add a variable (so skip the line
902 * otherwise). If both the section and name match, we need
903 * to overwrite the variable (so skip the line
904 * otherwise). pre_end needs to be updated each time so we
905 * don't loose that information, but we only need to
906 * update post_start if we're going to use it in this
909 if (!section_matches
) {
910 if (!last_section_matched
) {
911 cfg_consume_line(cfg
);
917 pre_end
= cfg
->reader
.read_ptr
;
918 if ((error
= parse_variable(cfg
, &var_name
, &var_value
)) == GIT_SUCCESS
)
919 cmp
= strcasecmp(name
, var_name
);
922 git__free(var_value
);
927 post_start
= cfg
->reader
.read_ptr
;
931 * We've found the variable we wanted to change, so
932 * write anything up to it
934 error
= git_filebuf_write(&file
, data_start
, pre_end
- data_start
);
935 if (error
< GIT_SUCCESS
) {
936 git__rethrow(error
, "Failed to write the first part of the file");
941 * Then replace the variable. If the value is NULL, it
942 * means we want to delete it, so pretend everything went
948 error
= git_filebuf_printf(&file
, "\t%s = %s\n", name
, value
);
949 if (error
< GIT_SUCCESS
) {
950 git__rethrow(error
, "Failed to overwrite the variable");
954 /* And then the write out rest of the file */
955 error
= git_filebuf_write(&file
, post_start
,
956 cfg
->reader
.buffer
.len
- (post_start
- data_start
));
958 if (error
< GIT_SUCCESS
) {
959 git__rethrow(error
, "Failed to write the rest of the file");
968 * Being here can mean that
970 * 1) our section is the last one in the file and we're
973 * 2) we didn't find a section for us so we need to create it
976 * Either way we need to write out the whole file.
979 error
= git_filebuf_write(&file
, cfg
->reader
.buffer
.data
, cfg
->reader
.buffer
.len
);
980 if (error
< GIT_SUCCESS
) {
981 git__rethrow(error
, "Failed to write original config content");
985 /* And now if we just need to add a variable */
986 if (section_matches
) {
987 error
= git_filebuf_printf(&file
, "\t%s = %s\n", name
, value
);
991 /* Or maybe we need to write out a whole section */
992 error
= write_section(&file
, section
);
993 if (error
< GIT_SUCCESS
)
994 git__rethrow(error
, "Failed to write new section");
996 error
= git_filebuf_printf(&file
, "\t%s = %s\n", name
, value
);
999 git__free(current_section
);
1001 if (error
< GIT_SUCCESS
)
1002 git_filebuf_cleanup(&file
);
1004 error
= git_filebuf_commit(&file
, GIT_CONFIG_FILE_MODE
);
1006 git_futils_freebuffer(&cfg
->reader
.buffer
);
1010 static int is_multiline_var(const char *str
)
1012 char *end
= strrchr(str
, '\0') - 1;
1014 while (isspace(*end
))
1017 return *end
== '\\';
1020 static int parse_multiline_variable(diskfile_backend
*cfg
, const char *first
, char **out
)
1022 char *line
= NULL
, *end
;
1023 int error
= GIT_SUCCESS
, ret
;
1027 /* Check that the next line exists */
1028 line
= cfg_readline(cfg
);
1032 /* We've reached the end of the file, there is input missing */
1033 if (line
[0] == '\0') {
1034 error
= git__throw(GIT_EOBJCORRUPTED
, "Failed to parse multiline var. File ended unexpectedly");
1038 strip_comments(line
);
1040 /* If it was just a comment, pretend it didn't exist */
1041 if (line
[0] == '\0') {
1042 error
= parse_multiline_variable(cfg
, first
, out
);
1046 /* Find the continuation character '\' and strip the whitespace */
1047 end
= strrchr(first
, '\\');
1048 while (isspace(end
[-1]))
1051 *end
= '\0'; /* Terminate the string here */
1053 len
= strlen(first
) + strlen(line
) + 2;
1054 buf
= git__malloc(len
);
1060 ret
= p_snprintf(buf
, len
, "%s %s", first
, line
);
1062 error
= git__throw(GIT_EOSERR
, "Failed to parse multiline var. Failed to put together two lines. OS err: %s", strerror(errno
));
1068 * If we need to continue reading the next line, pretend
1069 * everything we've read up to now was in one line and call
1072 if (is_multiline_var(buf
)) {
1074 error
= parse_multiline_variable(cfg
, buf
, &final_val
);
1086 static int parse_variable(diskfile_backend
*cfg
, char **var_name
, char **var_value
)
1089 int error
= GIT_SUCCESS
;
1090 const char *var_end
= NULL
;
1091 const char *value_start
= NULL
;
1094 line
= cfg_readline(cfg
);
1098 strip_comments(line
);
1100 var_end
= strchr(line
, '=');
1102 if (var_end
== NULL
)
1103 var_end
= strchr(line
, '\0');
1105 value_start
= var_end
+ 1;
1107 if (isspace(var_end
[-1])) {
1109 while (isspace(var_end
[0]));
1112 tmp
= git__strndup(line
, var_end
- line
+ 1);
1121 * Now, let's try to parse the value
1123 if (value_start
!= NULL
) {
1125 while (isspace(value_start
[0]))
1128 if (value_start
[0] == '\0') {
1133 if (is_multiline_var(value_start
)) {
1134 error
= parse_multiline_variable(cfg
, value_start
, var_value
);
1135 if (error
!= GIT_SUCCESS
)
1138 git__free(*var_name
);
1143 tmp
= git__strdup(value_start
);
1145 git__free(*var_name
);
1153 /* If there is no value, boolean true is assumed */