PageRenderTime 74ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 1ms

/cgit-0.9.0.2/git/config.c

#
C | 1484 lines | 1199 code | 161 blank | 124 comment | 380 complexity | dc28e9883ff1f6df06d4c4a3929d14a9 MD5 | raw file
Possible License(s): GPL-2.0, BSD-2-Clause
  1. /*
  2. * GIT - The information manager from hell
  3. *
  4. * Copyright (C) Linus Torvalds, 2005
  5. * Copyright (C) Johannes Schindelin, 2005
  6. *
  7. */
  8. #include "cache.h"
  9. #include "exec_cmd.h"
  10. #include "strbuf.h"
  11. #include "quote.h"
  12. #define MAXNAME (256)
  13. static FILE *config_file;
  14. static const char *config_file_name;
  15. static int config_linenr;
  16. static int config_file_eof;
  17. static int zlib_compression_seen;
  18. const char *config_exclusive_filename = NULL;
  19. struct config_item
  20. {
  21. struct config_item *next;
  22. char *name;
  23. char *value;
  24. };
  25. static struct config_item *config_parameters;
  26. static struct config_item **config_parameters_tail = &config_parameters;
  27. static void lowercase(char *p)
  28. {
  29. for (; *p; p++)
  30. *p = tolower(*p);
  31. }
  32. void git_config_push_parameter(const char *text)
  33. {
  34. struct strbuf env = STRBUF_INIT;
  35. const char *old = getenv(CONFIG_DATA_ENVIRONMENT);
  36. if (old) {
  37. strbuf_addstr(&env, old);
  38. strbuf_addch(&env, ' ');
  39. }
  40. sq_quote_buf(&env, text);
  41. setenv(CONFIG_DATA_ENVIRONMENT, env.buf, 1);
  42. strbuf_release(&env);
  43. }
  44. int git_config_parse_parameter(const char *text)
  45. {
  46. struct config_item *ct;
  47. struct strbuf tmp = STRBUF_INIT;
  48. struct strbuf **pair;
  49. strbuf_addstr(&tmp, text);
  50. pair = strbuf_split(&tmp, '=');
  51. if (pair[0]->len && pair[0]->buf[pair[0]->len - 1] == '=')
  52. strbuf_setlen(pair[0], pair[0]->len - 1);
  53. strbuf_trim(pair[0]);
  54. if (!pair[0]->len) {
  55. strbuf_list_free(pair);
  56. return -1;
  57. }
  58. ct = xcalloc(1, sizeof(struct config_item));
  59. ct->name = strbuf_detach(pair[0], NULL);
  60. if (pair[1]) {
  61. strbuf_trim(pair[1]);
  62. ct->value = strbuf_detach(pair[1], NULL);
  63. }
  64. strbuf_list_free(pair);
  65. lowercase(ct->name);
  66. *config_parameters_tail = ct;
  67. config_parameters_tail = &ct->next;
  68. return 0;
  69. }
  70. int git_config_parse_environment(void) {
  71. const char *env = getenv(CONFIG_DATA_ENVIRONMENT);
  72. char *envw;
  73. const char **argv = NULL;
  74. int nr = 0, alloc = 0;
  75. int i;
  76. if (!env)
  77. return 0;
  78. /* sq_dequote will write over it */
  79. envw = xstrdup(env);
  80. if (sq_dequote_to_argv(envw, &argv, &nr, &alloc) < 0) {
  81. free(envw);
  82. return error("bogus format in " CONFIG_DATA_ENVIRONMENT);
  83. }
  84. for (i = 0; i < nr; i++) {
  85. if (git_config_parse_parameter(argv[i]) < 0) {
  86. error("bogus config parameter: %s", argv[i]);
  87. free(argv);
  88. free(envw);
  89. return -1;
  90. }
  91. }
  92. free(argv);
  93. free(envw);
  94. return 0;
  95. }
  96. static int get_next_char(void)
  97. {
  98. int c;
  99. FILE *f;
  100. c = '\n';
  101. if ((f = config_file) != NULL) {
  102. c = fgetc(f);
  103. if (c == '\r') {
  104. /* DOS like systems */
  105. c = fgetc(f);
  106. if (c != '\n') {
  107. ungetc(c, f);
  108. c = '\r';
  109. }
  110. }
  111. if (c == '\n')
  112. config_linenr++;
  113. if (c == EOF) {
  114. config_file_eof = 1;
  115. c = '\n';
  116. }
  117. }
  118. return c;
  119. }
  120. static char *parse_value(void)
  121. {
  122. static char value[1024];
  123. int quote = 0, comment = 0, len = 0, space = 0;
  124. for (;;) {
  125. int c = get_next_char();
  126. if (len >= sizeof(value) - 1)
  127. return NULL;
  128. if (c == '\n') {
  129. if (quote)
  130. return NULL;
  131. value[len] = 0;
  132. return value;
  133. }
  134. if (comment)
  135. continue;
  136. if (isspace(c) && !quote) {
  137. if (len)
  138. space++;
  139. continue;
  140. }
  141. if (!quote) {
  142. if (c == ';' || c == '#') {
  143. comment = 1;
  144. continue;
  145. }
  146. }
  147. for (; space; space--)
  148. value[len++] = ' ';
  149. if (c == '\\') {
  150. c = get_next_char();
  151. switch (c) {
  152. case '\n':
  153. continue;
  154. case 't':
  155. c = '\t';
  156. break;
  157. case 'b':
  158. c = '\b';
  159. break;
  160. case 'n':
  161. c = '\n';
  162. break;
  163. /* Some characters escape as themselves */
  164. case '\\': case '"':
  165. break;
  166. /* Reject unknown escape sequences */
  167. default:
  168. return NULL;
  169. }
  170. value[len++] = c;
  171. continue;
  172. }
  173. if (c == '"') {
  174. quote = 1-quote;
  175. continue;
  176. }
  177. value[len++] = c;
  178. }
  179. }
  180. static inline int iskeychar(int c)
  181. {
  182. return isalnum(c) || c == '-';
  183. }
  184. static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
  185. {
  186. int c;
  187. char *value;
  188. /* Get the full name */
  189. for (;;) {
  190. c = get_next_char();
  191. if (config_file_eof)
  192. break;
  193. if (!iskeychar(c))
  194. break;
  195. name[len++] = tolower(c);
  196. if (len >= MAXNAME)
  197. return -1;
  198. }
  199. name[len] = 0;
  200. while (c == ' ' || c == '\t')
  201. c = get_next_char();
  202. value = NULL;
  203. if (c != '\n') {
  204. if (c != '=')
  205. return -1;
  206. value = parse_value();
  207. if (!value)
  208. return -1;
  209. }
  210. return fn(name, value, data);
  211. }
  212. static int get_extended_base_var(char *name, int baselen, int c)
  213. {
  214. do {
  215. if (c == '\n')
  216. return -1;
  217. c = get_next_char();
  218. } while (isspace(c));
  219. /* We require the format to be '[base "extension"]' */
  220. if (c != '"')
  221. return -1;
  222. name[baselen++] = '.';
  223. for (;;) {
  224. int c = get_next_char();
  225. if (c == '\n')
  226. return -1;
  227. if (c == '"')
  228. break;
  229. if (c == '\\') {
  230. c = get_next_char();
  231. if (c == '\n')
  232. return -1;
  233. }
  234. name[baselen++] = c;
  235. if (baselen > MAXNAME / 2)
  236. return -1;
  237. }
  238. /* Final ']' */
  239. if (get_next_char() != ']')
  240. return -1;
  241. return baselen;
  242. }
  243. static int get_base_var(char *name)
  244. {
  245. int baselen = 0;
  246. for (;;) {
  247. int c = get_next_char();
  248. if (config_file_eof)
  249. return -1;
  250. if (c == ']')
  251. return baselen;
  252. if (isspace(c))
  253. return get_extended_base_var(name, baselen, c);
  254. if (!iskeychar(c) && c != '.')
  255. return -1;
  256. if (baselen > MAXNAME / 2)
  257. return -1;
  258. name[baselen++] = tolower(c);
  259. }
  260. }
  261. static int git_parse_file(config_fn_t fn, void *data)
  262. {
  263. int comment = 0;
  264. int baselen = 0;
  265. static char var[MAXNAME];
  266. /* U+FEFF Byte Order Mark in UTF8 */
  267. static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
  268. const unsigned char *bomptr = utf8_bom;
  269. for (;;) {
  270. int c = get_next_char();
  271. if (bomptr && *bomptr) {
  272. /* We are at the file beginning; skip UTF8-encoded BOM
  273. * if present. Sane editors won't put this in on their
  274. * own, but e.g. Windows Notepad will do it happily. */
  275. if ((unsigned char) c == *bomptr) {
  276. bomptr++;
  277. continue;
  278. } else {
  279. /* Do not tolerate partial BOM. */
  280. if (bomptr != utf8_bom)
  281. break;
  282. /* No BOM at file beginning. Cool. */
  283. bomptr = NULL;
  284. }
  285. }
  286. if (c == '\n') {
  287. if (config_file_eof)
  288. return 0;
  289. comment = 0;
  290. continue;
  291. }
  292. if (comment || isspace(c))
  293. continue;
  294. if (c == '#' || c == ';') {
  295. comment = 1;
  296. continue;
  297. }
  298. if (c == '[') {
  299. baselen = get_base_var(var);
  300. if (baselen <= 0)
  301. break;
  302. var[baselen++] = '.';
  303. var[baselen] = 0;
  304. continue;
  305. }
  306. if (!isalpha(c))
  307. break;
  308. var[baselen] = tolower(c);
  309. if (get_value(fn, data, var, baselen+1) < 0)
  310. break;
  311. }
  312. die("bad config file line %d in %s", config_linenr, config_file_name);
  313. }
  314. static int parse_unit_factor(const char *end, unsigned long *val)
  315. {
  316. if (!*end)
  317. return 1;
  318. else if (!strcasecmp(end, "k")) {
  319. *val *= 1024;
  320. return 1;
  321. }
  322. else if (!strcasecmp(end, "m")) {
  323. *val *= 1024 * 1024;
  324. return 1;
  325. }
  326. else if (!strcasecmp(end, "g")) {
  327. *val *= 1024 * 1024 * 1024;
  328. return 1;
  329. }
  330. return 0;
  331. }
  332. static int git_parse_long(const char *value, long *ret)
  333. {
  334. if (value && *value) {
  335. char *end;
  336. long val = strtol(value, &end, 0);
  337. unsigned long factor = 1;
  338. if (!parse_unit_factor(end, &factor))
  339. return 0;
  340. *ret = val * factor;
  341. return 1;
  342. }
  343. return 0;
  344. }
  345. int git_parse_ulong(const char *value, unsigned long *ret)
  346. {
  347. if (value && *value) {
  348. char *end;
  349. unsigned long val = strtoul(value, &end, 0);
  350. if (!parse_unit_factor(end, &val))
  351. return 0;
  352. *ret = val;
  353. return 1;
  354. }
  355. return 0;
  356. }
  357. static void die_bad_config(const char *name)
  358. {
  359. if (config_file_name)
  360. die("bad config value for '%s' in %s", name, config_file_name);
  361. die("bad config value for '%s'", name);
  362. }
  363. int git_config_int(const char *name, const char *value)
  364. {
  365. long ret = 0;
  366. if (!git_parse_long(value, &ret))
  367. die_bad_config(name);
  368. return ret;
  369. }
  370. unsigned long git_config_ulong(const char *name, const char *value)
  371. {
  372. unsigned long ret;
  373. if (!git_parse_ulong(value, &ret))
  374. die_bad_config(name);
  375. return ret;
  376. }
  377. static int git_config_maybe_bool_text(const char *name, const char *value)
  378. {
  379. if (!value)
  380. return 1;
  381. if (!*value)
  382. return 0;
  383. if (!strcasecmp(value, "true")
  384. || !strcasecmp(value, "yes")
  385. || !strcasecmp(value, "on"))
  386. return 1;
  387. if (!strcasecmp(value, "false")
  388. || !strcasecmp(value, "no")
  389. || !strcasecmp(value, "off"))
  390. return 0;
  391. return -1;
  392. }
  393. int git_config_maybe_bool(const char *name, const char *value)
  394. {
  395. long v = git_config_maybe_bool_text(name, value);
  396. if (0 <= v)
  397. return v;
  398. if (git_parse_long(value, &v))
  399. return !!v;
  400. return -1;
  401. }
  402. int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
  403. {
  404. int v = git_config_maybe_bool_text(name, value);
  405. if (0 <= v) {
  406. *is_bool = 1;
  407. return v;
  408. }
  409. *is_bool = 0;
  410. return git_config_int(name, value);
  411. }
  412. int git_config_bool(const char *name, const char *value)
  413. {
  414. int discard;
  415. return !!git_config_bool_or_int(name, value, &discard);
  416. }
  417. int git_config_string(const char **dest, const char *var, const char *value)
  418. {
  419. if (!value)
  420. return config_error_nonbool(var);
  421. *dest = xstrdup(value);
  422. return 0;
  423. }
  424. int git_config_pathname(const char **dest, const char *var, const char *value)
  425. {
  426. if (!value)
  427. return config_error_nonbool(var);
  428. *dest = expand_user_path(value);
  429. if (!*dest)
  430. die("Failed to expand user dir in: '%s'", value);
  431. return 0;
  432. }
  433. static int git_default_core_config(const char *var, const char *value)
  434. {
  435. /* This needs a better name */
  436. if (!strcmp(var, "core.filemode")) {
  437. trust_executable_bit = git_config_bool(var, value);
  438. return 0;
  439. }
  440. if (!strcmp(var, "core.trustctime")) {
  441. trust_ctime = git_config_bool(var, value);
  442. return 0;
  443. }
  444. if (!strcmp(var, "core.quotepath")) {
  445. quote_path_fully = git_config_bool(var, value);
  446. return 0;
  447. }
  448. if (!strcmp(var, "core.symlinks")) {
  449. has_symlinks = git_config_bool(var, value);
  450. return 0;
  451. }
  452. if (!strcmp(var, "core.ignorecase")) {
  453. ignore_case = git_config_bool(var, value);
  454. return 0;
  455. }
  456. if (!strcmp(var, "core.abbrevguard")) {
  457. unique_abbrev_extra_length = git_config_int(var, value);
  458. if (unique_abbrev_extra_length < 0)
  459. unique_abbrev_extra_length = 0;
  460. return 0;
  461. }
  462. if (!strcmp(var, "core.bare")) {
  463. is_bare_repository_cfg = git_config_bool(var, value);
  464. return 0;
  465. }
  466. if (!strcmp(var, "core.ignorestat")) {
  467. assume_unchanged = git_config_bool(var, value);
  468. return 0;
  469. }
  470. if (!strcmp(var, "core.prefersymlinkrefs")) {
  471. prefer_symlink_refs = git_config_bool(var, value);
  472. return 0;
  473. }
  474. if (!strcmp(var, "core.logallrefupdates")) {
  475. log_all_ref_updates = git_config_bool(var, value);
  476. return 0;
  477. }
  478. if (!strcmp(var, "core.warnambiguousrefs")) {
  479. warn_ambiguous_refs = git_config_bool(var, value);
  480. return 0;
  481. }
  482. if (!strcmp(var, "core.loosecompression")) {
  483. int level = git_config_int(var, value);
  484. if (level == -1)
  485. level = Z_DEFAULT_COMPRESSION;
  486. else if (level < 0 || level > Z_BEST_COMPRESSION)
  487. die("bad zlib compression level %d", level);
  488. zlib_compression_level = level;
  489. zlib_compression_seen = 1;
  490. return 0;
  491. }
  492. if (!strcmp(var, "core.compression")) {
  493. int level = git_config_int(var, value);
  494. if (level == -1)
  495. level = Z_DEFAULT_COMPRESSION;
  496. else if (level < 0 || level > Z_BEST_COMPRESSION)
  497. die("bad zlib compression level %d", level);
  498. core_compression_level = level;
  499. core_compression_seen = 1;
  500. if (!zlib_compression_seen)
  501. zlib_compression_level = level;
  502. return 0;
  503. }
  504. if (!strcmp(var, "core.packedgitwindowsize")) {
  505. int pgsz_x2 = getpagesize() * 2;
  506. packed_git_window_size = git_config_int(var, value);
  507. /* This value must be multiple of (pagesize * 2) */
  508. packed_git_window_size /= pgsz_x2;
  509. if (packed_git_window_size < 1)
  510. packed_git_window_size = 1;
  511. packed_git_window_size *= pgsz_x2;
  512. return 0;
  513. }
  514. if (!strcmp(var, "core.packedgitlimit")) {
  515. packed_git_limit = git_config_int(var, value);
  516. return 0;
  517. }
  518. if (!strcmp(var, "core.deltabasecachelimit")) {
  519. delta_base_cache_limit = git_config_int(var, value);
  520. return 0;
  521. }
  522. if (!strcmp(var, "core.autocrlf")) {
  523. if (value && !strcasecmp(value, "input")) {
  524. if (eol == EOL_CRLF)
  525. return error("core.autocrlf=input conflicts with core.eol=crlf");
  526. auto_crlf = AUTO_CRLF_INPUT;
  527. return 0;
  528. }
  529. auto_crlf = git_config_bool(var, value);
  530. return 0;
  531. }
  532. if (!strcmp(var, "core.safecrlf")) {
  533. if (value && !strcasecmp(value, "warn")) {
  534. safe_crlf = SAFE_CRLF_WARN;
  535. return 0;
  536. }
  537. safe_crlf = git_config_bool(var, value);
  538. return 0;
  539. }
  540. if (!strcmp(var, "core.eol")) {
  541. if (value && !strcasecmp(value, "lf"))
  542. eol = EOL_LF;
  543. else if (value && !strcasecmp(value, "crlf"))
  544. eol = EOL_CRLF;
  545. else if (value && !strcasecmp(value, "native"))
  546. eol = EOL_NATIVE;
  547. else
  548. eol = EOL_UNSET;
  549. if (eol == EOL_CRLF && auto_crlf == AUTO_CRLF_INPUT)
  550. return error("core.autocrlf=input conflicts with core.eol=crlf");
  551. return 0;
  552. }
  553. if (!strcmp(var, "core.notesref")) {
  554. notes_ref_name = xstrdup(value);
  555. return 0;
  556. }
  557. if (!strcmp(var, "core.pager"))
  558. return git_config_string(&pager_program, var, value);
  559. if (!strcmp(var, "core.editor"))
  560. return git_config_string(&editor_program, var, value);
  561. if (!strcmp(var, "core.askpass"))
  562. return git_config_string(&askpass_program, var, value);
  563. if (!strcmp(var, "core.excludesfile"))
  564. return git_config_pathname(&excludes_file, var, value);
  565. if (!strcmp(var, "core.whitespace")) {
  566. if (!value)
  567. return config_error_nonbool(var);
  568. whitespace_rule_cfg = parse_whitespace_rule(value);
  569. return 0;
  570. }
  571. if (!strcmp(var, "core.fsyncobjectfiles")) {
  572. fsync_object_files = git_config_bool(var, value);
  573. return 0;
  574. }
  575. if (!strcmp(var, "core.preloadindex")) {
  576. core_preload_index = git_config_bool(var, value);
  577. return 0;
  578. }
  579. if (!strcmp(var, "core.createobject")) {
  580. if (!strcmp(value, "rename"))
  581. object_creation_mode = OBJECT_CREATION_USES_RENAMES;
  582. else if (!strcmp(value, "link"))
  583. object_creation_mode = OBJECT_CREATION_USES_HARDLINKS;
  584. else
  585. die("Invalid mode for object creation: %s", value);
  586. return 0;
  587. }
  588. if (!strcmp(var, "core.sparsecheckout")) {
  589. core_apply_sparse_checkout = git_config_bool(var, value);
  590. return 0;
  591. }
  592. /* Add other config variables here and to Documentation/config.txt. */
  593. return 0;
  594. }
  595. static int git_default_user_config(const char *var, const char *value)
  596. {
  597. if (!strcmp(var, "user.name")) {
  598. if (!value)
  599. return config_error_nonbool(var);
  600. strlcpy(git_default_name, value, sizeof(git_default_name));
  601. user_ident_explicitly_given |= IDENT_NAME_GIVEN;
  602. return 0;
  603. }
  604. if (!strcmp(var, "user.email")) {
  605. if (!value)
  606. return config_error_nonbool(var);
  607. strlcpy(git_default_email, value, sizeof(git_default_email));
  608. user_ident_explicitly_given |= IDENT_MAIL_GIVEN;
  609. return 0;
  610. }
  611. /* Add other config variables here and to Documentation/config.txt. */
  612. return 0;
  613. }
  614. static int git_default_i18n_config(const char *var, const char *value)
  615. {
  616. if (!strcmp(var, "i18n.commitencoding"))
  617. return git_config_string(&git_commit_encoding, var, value);
  618. if (!strcmp(var, "i18n.logoutputencoding"))
  619. return git_config_string(&git_log_output_encoding, var, value);
  620. /* Add other config variables here and to Documentation/config.txt. */
  621. return 0;
  622. }
  623. static int git_default_branch_config(const char *var, const char *value)
  624. {
  625. if (!strcmp(var, "branch.autosetupmerge")) {
  626. if (value && !strcasecmp(value, "always")) {
  627. git_branch_track = BRANCH_TRACK_ALWAYS;
  628. return 0;
  629. }
  630. git_branch_track = git_config_bool(var, value);
  631. return 0;
  632. }
  633. if (!strcmp(var, "branch.autosetuprebase")) {
  634. if (!value)
  635. return config_error_nonbool(var);
  636. else if (!strcmp(value, "never"))
  637. autorebase = AUTOREBASE_NEVER;
  638. else if (!strcmp(value, "local"))
  639. autorebase = AUTOREBASE_LOCAL;
  640. else if (!strcmp(value, "remote"))
  641. autorebase = AUTOREBASE_REMOTE;
  642. else if (!strcmp(value, "always"))
  643. autorebase = AUTOREBASE_ALWAYS;
  644. else
  645. return error("Malformed value for %s", var);
  646. return 0;
  647. }
  648. /* Add other config variables here and to Documentation/config.txt. */
  649. return 0;
  650. }
  651. static int git_default_push_config(const char *var, const char *value)
  652. {
  653. if (!strcmp(var, "push.default")) {
  654. if (!value)
  655. return config_error_nonbool(var);
  656. else if (!strcmp(value, "nothing"))
  657. push_default = PUSH_DEFAULT_NOTHING;
  658. else if (!strcmp(value, "matching"))
  659. push_default = PUSH_DEFAULT_MATCHING;
  660. else if (!strcmp(value, "tracking"))
  661. push_default = PUSH_DEFAULT_TRACKING;
  662. else if (!strcmp(value, "current"))
  663. push_default = PUSH_DEFAULT_CURRENT;
  664. else {
  665. error("Malformed value for %s: %s", var, value);
  666. return error("Must be one of nothing, matching, "
  667. "tracking or current.");
  668. }
  669. return 0;
  670. }
  671. /* Add other config variables here and to Documentation/config.txt. */
  672. return 0;
  673. }
  674. static int git_default_mailmap_config(const char *var, const char *value)
  675. {
  676. if (!strcmp(var, "mailmap.file"))
  677. return git_config_string(&git_mailmap_file, var, value);
  678. /* Add other config variables here and to Documentation/config.txt. */
  679. return 0;
  680. }
  681. int git_default_config(const char *var, const char *value, void *dummy)
  682. {
  683. if (!prefixcmp(var, "core."))
  684. return git_default_core_config(var, value);
  685. if (!prefixcmp(var, "user."))
  686. return git_default_user_config(var, value);
  687. if (!prefixcmp(var, "i18n."))
  688. return git_default_i18n_config(var, value);
  689. if (!prefixcmp(var, "branch."))
  690. return git_default_branch_config(var, value);
  691. if (!prefixcmp(var, "push."))
  692. return git_default_push_config(var, value);
  693. if (!prefixcmp(var, "mailmap."))
  694. return git_default_mailmap_config(var, value);
  695. if (!prefixcmp(var, "advice."))
  696. return git_default_advice_config(var, value);
  697. if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
  698. pager_use_color = git_config_bool(var,value);
  699. return 0;
  700. }
  701. /* Add other config variables here and to Documentation/config.txt. */
  702. return 0;
  703. }
  704. int git_config_from_file(config_fn_t fn, const char *filename, void *data)
  705. {
  706. int ret;
  707. FILE *f = fopen(filename, "r");
  708. ret = -1;
  709. if (f) {
  710. config_file = f;
  711. config_file_name = filename;
  712. config_linenr = 1;
  713. config_file_eof = 0;
  714. ret = git_parse_file(fn, data);
  715. fclose(f);
  716. config_file_name = NULL;
  717. }
  718. return ret;
  719. }
  720. const char *git_etc_gitconfig(void)
  721. {
  722. static const char *system_wide;
  723. if (!system_wide)
  724. system_wide = system_path(ETC_GITCONFIG);
  725. return system_wide;
  726. }
  727. int git_env_bool(const char *k, int def)
  728. {
  729. const char *v = getenv(k);
  730. return v ? git_config_bool(k, v) : def;
  731. }
  732. int git_config_system(void)
  733. {
  734. return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
  735. }
  736. int git_config_global(void)
  737. {
  738. return !git_env_bool("GIT_CONFIG_NOGLOBAL", 0);
  739. }
  740. int git_config_from_parameters(config_fn_t fn, void *data)
  741. {
  742. static int loaded_environment;
  743. const struct config_item *ct;
  744. if (!loaded_environment) {
  745. if (git_config_parse_environment() < 0)
  746. return -1;
  747. loaded_environment = 1;
  748. }
  749. for (ct = config_parameters; ct; ct = ct->next)
  750. if (fn(ct->name, ct->value, data) < 0)
  751. return -1;
  752. return 0;
  753. }
  754. int git_config_early(config_fn_t fn, void *data, const char *repo_config)
  755. {
  756. int ret = 0, found = 0;
  757. const char *home = NULL;
  758. /* Setting $GIT_CONFIG makes git read _only_ the given config file. */
  759. if (config_exclusive_filename)
  760. return git_config_from_file(fn, config_exclusive_filename, data);
  761. if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) {
  762. ret += git_config_from_file(fn, git_etc_gitconfig(),
  763. data);
  764. found += 1;
  765. }
  766. home = getenv("HOME");
  767. if (git_config_global() && home) {
  768. char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
  769. if (!access(user_config, R_OK)) {
  770. ret += git_config_from_file(fn, user_config, data);
  771. found += 1;
  772. }
  773. free(user_config);
  774. }
  775. if (repo_config && !access(repo_config, R_OK)) {
  776. ret += git_config_from_file(fn, repo_config, data);
  777. found += 1;
  778. }
  779. ret += git_config_from_parameters(fn, data);
  780. if (config_parameters)
  781. found += 1;
  782. return ret == 0 ? found : ret;
  783. }
  784. int git_config(config_fn_t fn, void *data)
  785. {
  786. char *repo_config = NULL;
  787. int ret;
  788. repo_config = git_pathdup("config");
  789. ret = git_config_early(fn, data, repo_config);
  790. if (repo_config)
  791. free(repo_config);
  792. return ret;
  793. }
  794. /*
  795. * Find all the stuff for git_config_set() below.
  796. */
  797. #define MAX_MATCHES 512
  798. static struct {
  799. int baselen;
  800. char *key;
  801. int do_not_match;
  802. regex_t *value_regex;
  803. int multi_replace;
  804. size_t offset[MAX_MATCHES];
  805. enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
  806. int seen;
  807. } store;
  808. static int matches(const char *key, const char *value)
  809. {
  810. return !strcmp(key, store.key) &&
  811. (store.value_regex == NULL ||
  812. (store.do_not_match ^
  813. !regexec(store.value_regex, value, 0, NULL, 0)));
  814. }
  815. static int store_aux(const char *key, const char *value, void *cb)
  816. {
  817. const char *ep;
  818. size_t section_len;
  819. switch (store.state) {
  820. case KEY_SEEN:
  821. if (matches(key, value)) {
  822. if (store.seen == 1 && store.multi_replace == 0) {
  823. warning("%s has multiple values", key);
  824. } else if (store.seen >= MAX_MATCHES) {
  825. error("too many matches for %s", key);
  826. return 1;
  827. }
  828. store.offset[store.seen] = ftell(config_file);
  829. store.seen++;
  830. }
  831. break;
  832. case SECTION_SEEN:
  833. /*
  834. * What we are looking for is in store.key (both
  835. * section and var), and its section part is baselen
  836. * long. We found key (again, both section and var).
  837. * We would want to know if this key is in the same
  838. * section as what we are looking for. We already
  839. * know we are in the same section as what should
  840. * hold store.key.
  841. */
  842. ep = strrchr(key, '.');
  843. section_len = ep - key;
  844. if ((section_len != store.baselen) ||
  845. memcmp(key, store.key, section_len+1)) {
  846. store.state = SECTION_END_SEEN;
  847. break;
  848. }
  849. /*
  850. * Do not increment matches: this is no match, but we
  851. * just made sure we are in the desired section.
  852. */
  853. store.offset[store.seen] = ftell(config_file);
  854. /* fallthru */
  855. case SECTION_END_SEEN:
  856. case START:
  857. if (matches(key, value)) {
  858. store.offset[store.seen] = ftell(config_file);
  859. store.state = KEY_SEEN;
  860. store.seen++;
  861. } else {
  862. if (strrchr(key, '.') - key == store.baselen &&
  863. !strncmp(key, store.key, store.baselen)) {
  864. store.state = SECTION_SEEN;
  865. store.offset[store.seen] = ftell(config_file);
  866. }
  867. }
  868. }
  869. return 0;
  870. }
  871. static int write_error(const char *filename)
  872. {
  873. error("failed to write new configuration file %s", filename);
  874. /* Same error code as "failed to rename". */
  875. return 4;
  876. }
  877. static int store_write_section(int fd, const char *key)
  878. {
  879. const char *dot;
  880. int i, success;
  881. struct strbuf sb = STRBUF_INIT;
  882. dot = memchr(key, '.', store.baselen);
  883. if (dot) {
  884. strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
  885. for (i = dot - key + 1; i < store.baselen; i++) {
  886. if (key[i] == '"' || key[i] == '\\')
  887. strbuf_addch(&sb, '\\');
  888. strbuf_addch(&sb, key[i]);
  889. }
  890. strbuf_addstr(&sb, "\"]\n");
  891. } else {
  892. strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
  893. }
  894. success = write_in_full(fd, sb.buf, sb.len) == sb.len;
  895. strbuf_release(&sb);
  896. return success;
  897. }
  898. static int store_write_pair(int fd, const char *key, const char *value)
  899. {
  900. int i, success;
  901. int length = strlen(key + store.baselen + 1);
  902. const char *quote = "";
  903. struct strbuf sb = STRBUF_INIT;
  904. /*
  905. * Check to see if the value needs to be surrounded with a dq pair.
  906. * Note that problematic characters are always backslash-quoted; this
  907. * check is about not losing leading or trailing SP and strings that
  908. * follow beginning-of-comment characters (i.e. ';' and '#') by the
  909. * configuration parser.
  910. */
  911. if (value[0] == ' ')
  912. quote = "\"";
  913. for (i = 0; value[i]; i++)
  914. if (value[i] == ';' || value[i] == '#')
  915. quote = "\"";
  916. if (i && value[i - 1] == ' ')
  917. quote = "\"";
  918. strbuf_addf(&sb, "\t%.*s = %s",
  919. length, key + store.baselen + 1, quote);
  920. for (i = 0; value[i]; i++)
  921. switch (value[i]) {
  922. case '\n':
  923. strbuf_addstr(&sb, "\\n");
  924. break;
  925. case '\t':
  926. strbuf_addstr(&sb, "\\t");
  927. break;
  928. case '"':
  929. case '\\':
  930. strbuf_addch(&sb, '\\');
  931. default:
  932. strbuf_addch(&sb, value[i]);
  933. break;
  934. }
  935. strbuf_addf(&sb, "%s\n", quote);
  936. success = write_in_full(fd, sb.buf, sb.len) == sb.len;
  937. strbuf_release(&sb);
  938. return success;
  939. }
  940. static ssize_t find_beginning_of_line(const char *contents, size_t size,
  941. size_t offset_, int *found_bracket)
  942. {
  943. size_t equal_offset = size, bracket_offset = size;
  944. ssize_t offset;
  945. contline:
  946. for (offset = offset_-2; offset > 0
  947. && contents[offset] != '\n'; offset--)
  948. switch (contents[offset]) {
  949. case '=': equal_offset = offset; break;
  950. case ']': bracket_offset = offset; break;
  951. }
  952. if (offset > 0 && contents[offset-1] == '\\') {
  953. offset_ = offset;
  954. goto contline;
  955. }
  956. if (bracket_offset < equal_offset) {
  957. *found_bracket = 1;
  958. offset = bracket_offset+1;
  959. } else
  960. offset++;
  961. return offset;
  962. }
  963. int git_config_set(const char *key, const char *value)
  964. {
  965. return git_config_set_multivar(key, value, NULL, 0);
  966. }
  967. /*
  968. * If value==NULL, unset in (remove from) config,
  969. * if value_regex!=NULL, disregard key/value pairs where value does not match.
  970. * if multi_replace==0, nothing, or only one matching key/value is replaced,
  971. * else all matching key/values (regardless how many) are removed,
  972. * before the new pair is written.
  973. *
  974. * Returns 0 on success.
  975. *
  976. * This function does this:
  977. *
  978. * - it locks the config file by creating ".git/config.lock"
  979. *
  980. * - it then parses the config using store_aux() as validator to find
  981. * the position on the key/value pair to replace. If it is to be unset,
  982. * it must be found exactly once.
  983. *
  984. * - the config file is mmap()ed and the part before the match (if any) is
  985. * written to the lock file, then the changed part and the rest.
  986. *
  987. * - the config file is removed and the lock file rename()d to it.
  988. *
  989. */
  990. int git_config_set_multivar(const char *key, const char *value,
  991. const char *value_regex, int multi_replace)
  992. {
  993. int i, dot;
  994. int fd = -1, in_fd;
  995. int ret;
  996. char *config_filename;
  997. struct lock_file *lock = NULL;
  998. const char *last_dot = strrchr(key, '.');
  999. if (config_exclusive_filename)
  1000. config_filename = xstrdup(config_exclusive_filename);
  1001. else
  1002. config_filename = git_pathdup("config");
  1003. /*
  1004. * Since "key" actually contains the section name and the real
  1005. * key name separated by a dot, we have to know where the dot is.
  1006. */
  1007. if (last_dot == NULL) {
  1008. error("key does not contain a section: %s", key);
  1009. ret = 2;
  1010. goto out_free;
  1011. }
  1012. store.baselen = last_dot - key;
  1013. store.multi_replace = multi_replace;
  1014. /*
  1015. * Validate the key and while at it, lower case it for matching.
  1016. */
  1017. store.key = xmalloc(strlen(key) + 1);
  1018. dot = 0;
  1019. for (i = 0; key[i]; i++) {
  1020. unsigned char c = key[i];
  1021. if (c == '.')
  1022. dot = 1;
  1023. /* Leave the extended basename untouched.. */
  1024. if (!dot || i > store.baselen) {
  1025. if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) {
  1026. error("invalid key: %s", key);
  1027. free(store.key);
  1028. ret = 1;
  1029. goto out_free;
  1030. }
  1031. c = tolower(c);
  1032. } else if (c == '\n') {
  1033. error("invalid key (newline): %s", key);
  1034. free(store.key);
  1035. ret = 1;
  1036. goto out_free;
  1037. }
  1038. store.key[i] = c;
  1039. }
  1040. store.key[i] = 0;
  1041. /*
  1042. * The lock serves a purpose in addition to locking: the new
  1043. * contents of .git/config will be written into it.
  1044. */
  1045. lock = xcalloc(sizeof(struct lock_file), 1);
  1046. fd = hold_lock_file_for_update(lock, config_filename, 0);
  1047. if (fd < 0) {
  1048. error("could not lock config file %s: %s", config_filename, strerror(errno));
  1049. free(store.key);
  1050. ret = -1;
  1051. goto out_free;
  1052. }
  1053. /*
  1054. * If .git/config does not exist yet, write a minimal version.
  1055. */
  1056. in_fd = open(config_filename, O_RDONLY);
  1057. if ( in_fd < 0 ) {
  1058. free(store.key);
  1059. if ( ENOENT != errno ) {
  1060. error("opening %s: %s", config_filename,
  1061. strerror(errno));
  1062. ret = 3; /* same as "invalid config file" */
  1063. goto out_free;
  1064. }
  1065. /* if nothing to unset, error out */
  1066. if (value == NULL) {
  1067. ret = 5;
  1068. goto out_free;
  1069. }
  1070. store.key = (char *)key;
  1071. if (!store_write_section(fd, key) ||
  1072. !store_write_pair(fd, key, value))
  1073. goto write_err_out;
  1074. } else {
  1075. struct stat st;
  1076. char *contents;
  1077. size_t contents_sz, copy_begin, copy_end;
  1078. int i, new_line = 0;
  1079. if (value_regex == NULL)
  1080. store.value_regex = NULL;
  1081. else {
  1082. if (value_regex[0] == '!') {
  1083. store.do_not_match = 1;
  1084. value_regex++;
  1085. } else
  1086. store.do_not_match = 0;
  1087. store.value_regex = (regex_t*)xmalloc(sizeof(regex_t));
  1088. if (regcomp(store.value_regex, value_regex,
  1089. REG_EXTENDED)) {
  1090. error("invalid pattern: %s", value_regex);
  1091. free(store.value_regex);
  1092. ret = 6;
  1093. goto out_free;
  1094. }
  1095. }
  1096. store.offset[0] = 0;
  1097. store.state = START;
  1098. store.seen = 0;
  1099. /*
  1100. * After this, store.offset will contain the *end* offset
  1101. * of the last match, or remain at 0 if no match was found.
  1102. * As a side effect, we make sure to transform only a valid
  1103. * existing config file.
  1104. */
  1105. if (git_config_from_file(store_aux, config_filename, NULL)) {
  1106. error("invalid config file %s", config_filename);
  1107. free(store.key);
  1108. if (store.value_regex != NULL) {
  1109. regfree(store.value_regex);
  1110. free(store.value_regex);
  1111. }
  1112. ret = 3;
  1113. goto out_free;
  1114. }
  1115. free(store.key);
  1116. if (store.value_regex != NULL) {
  1117. regfree(store.value_regex);
  1118. free(store.value_regex);
  1119. }
  1120. /* if nothing to unset, or too many matches, error out */
  1121. if ((store.seen == 0 && value == NULL) ||
  1122. (store.seen > 1 && multi_replace == 0)) {
  1123. ret = 5;
  1124. goto out_free;
  1125. }
  1126. fstat(in_fd, &st);
  1127. contents_sz = xsize_t(st.st_size);
  1128. contents = xmmap(NULL, contents_sz, PROT_READ,
  1129. MAP_PRIVATE, in_fd, 0);
  1130. close(in_fd);
  1131. if (store.seen == 0)
  1132. store.seen = 1;
  1133. for (i = 0, copy_begin = 0; i < store.seen; i++) {
  1134. if (store.offset[i] == 0) {
  1135. store.offset[i] = copy_end = contents_sz;
  1136. } else if (store.state != KEY_SEEN) {
  1137. copy_end = store.offset[i];
  1138. } else
  1139. copy_end = find_beginning_of_line(
  1140. contents, contents_sz,
  1141. store.offset[i]-2, &new_line);
  1142. if (copy_end > 0 && contents[copy_end-1] != '\n')
  1143. new_line = 1;
  1144. /* write the first part of the config */
  1145. if (copy_end > copy_begin) {
  1146. if (write_in_full(fd, contents + copy_begin,
  1147. copy_end - copy_begin) <
  1148. copy_end - copy_begin)
  1149. goto write_err_out;
  1150. if (new_line &&
  1151. write_str_in_full(fd, "\n") != 1)
  1152. goto write_err_out;
  1153. }
  1154. copy_begin = store.offset[i];
  1155. }
  1156. /* write the pair (value == NULL means unset) */
  1157. if (value != NULL) {
  1158. if (store.state == START) {
  1159. if (!store_write_section(fd, key))
  1160. goto write_err_out;
  1161. }
  1162. if (!store_write_pair(fd, key, value))
  1163. goto write_err_out;
  1164. }
  1165. /* write the rest of the config */
  1166. if (copy_begin < contents_sz)
  1167. if (write_in_full(fd, contents + copy_begin,
  1168. contents_sz - copy_begin) <
  1169. contents_sz - copy_begin)
  1170. goto write_err_out;
  1171. munmap(contents, contents_sz);
  1172. }
  1173. if (commit_lock_file(lock) < 0) {
  1174. error("could not commit config file %s", config_filename);
  1175. ret = 4;
  1176. goto out_free;
  1177. }
  1178. /*
  1179. * lock is committed, so don't try to roll it back below.
  1180. * NOTE: Since lockfile.c keeps a linked list of all created
  1181. * lock_file structures, it isn't safe to free(lock). It's
  1182. * better to just leave it hanging around.
  1183. */
  1184. lock = NULL;
  1185. ret = 0;
  1186. out_free:
  1187. if (lock)
  1188. rollback_lock_file(lock);
  1189. free(config_filename);
  1190. return ret;
  1191. write_err_out:
  1192. ret = write_error(lock->filename);
  1193. goto out_free;
  1194. }
  1195. static int section_name_match (const char *buf, const char *name)
  1196. {
  1197. int i = 0, j = 0, dot = 0;
  1198. if (buf[i] != '[')
  1199. return 0;
  1200. for (i = 1; buf[i] && buf[i] != ']'; i++) {
  1201. if (!dot && isspace(buf[i])) {
  1202. dot = 1;
  1203. if (name[j++] != '.')
  1204. break;
  1205. for (i++; isspace(buf[i]); i++)
  1206. ; /* do nothing */
  1207. if (buf[i] != '"')
  1208. break;
  1209. continue;
  1210. }
  1211. if (buf[i] == '\\' && dot)
  1212. i++;
  1213. else if (buf[i] == '"' && dot) {
  1214. for (i++; isspace(buf[i]); i++)
  1215. ; /* do_nothing */
  1216. break;
  1217. }
  1218. if (buf[i] != name[j++])
  1219. break;
  1220. }
  1221. if (buf[i] == ']' && name[j] == 0) {
  1222. /*
  1223. * We match, now just find the right length offset by
  1224. * gobbling up any whitespace after it, as well
  1225. */
  1226. i++;
  1227. for (; buf[i] && isspace(buf[i]); i++)
  1228. ; /* do nothing */
  1229. return i;
  1230. }
  1231. return 0;
  1232. }
  1233. /* if new_name == NULL, the section is removed instead */
  1234. int git_config_rename_section(const char *old_name, const char *new_name)
  1235. {
  1236. int ret = 0, remove = 0;
  1237. char *config_filename;
  1238. struct lock_file *lock = xcalloc(sizeof(struct lock_file), 1);
  1239. int out_fd;
  1240. char buf[1024];
  1241. if (config_exclusive_filename)
  1242. config_filename = xstrdup(config_exclusive_filename);
  1243. else
  1244. config_filename = git_pathdup("config");
  1245. out_fd = hold_lock_file_for_update(lock, config_filename, 0);
  1246. if (out_fd < 0) {
  1247. ret = error("could not lock config file %s", config_filename);
  1248. goto out;
  1249. }
  1250. if (!(config_file = fopen(config_filename, "rb"))) {
  1251. /* no config file means nothing to rename, no error */
  1252. goto unlock_and_out;
  1253. }
  1254. while (fgets(buf, sizeof(buf), config_file)) {
  1255. int i;
  1256. int length;
  1257. char *output = buf;
  1258. for (i = 0; buf[i] && isspace(buf[i]); i++)
  1259. ; /* do nothing */
  1260. if (buf[i] == '[') {
  1261. /* it's a section */
  1262. int offset = section_name_match(&buf[i], old_name);
  1263. if (offset > 0) {
  1264. ret++;
  1265. if (new_name == NULL) {
  1266. remove = 1;
  1267. continue;
  1268. }
  1269. store.baselen = strlen(new_name);
  1270. if (!store_write_section(out_fd, new_name)) {
  1271. ret = write_error(lock->filename);
  1272. goto out;
  1273. }
  1274. /*
  1275. * We wrote out the new section, with
  1276. * a newline, now skip the old
  1277. * section's length
  1278. */
  1279. output += offset + i;
  1280. if (strlen(output) > 0) {
  1281. /*
  1282. * More content means there's
  1283. * a declaration to put on the
  1284. * next line; indent with a
  1285. * tab
  1286. */
  1287. output -= 1;
  1288. output[0] = '\t';
  1289. }
  1290. }
  1291. remove = 0;
  1292. }
  1293. if (remove)
  1294. continue;
  1295. length = strlen(output);
  1296. if (write_in_full(out_fd, output, length) != length) {
  1297. ret = write_error(lock->filename);
  1298. goto out;
  1299. }
  1300. }
  1301. fclose(config_file);
  1302. unlock_and_out:
  1303. if (commit_lock_file(lock) < 0)
  1304. ret = error("could not commit config file %s", config_filename);
  1305. out:
  1306. free(config_filename);
  1307. return ret;
  1308. }
  1309. /*
  1310. * Call this to report error for your variable that should not
  1311. * get a boolean value (i.e. "[my] var" means "true").
  1312. */
  1313. int config_error_nonbool(const char *var)
  1314. {
  1315. return error("Missing value for '%s'", var);
  1316. }