rugged 0.26.7 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/ext/rugged/rugged_blame.c +6 -3
  4. data/ext/rugged/rugged_branch_collection.c +3 -6
  5. data/ext/rugged/rugged_commit.c +56 -0
  6. data/ext/rugged/rugged_config.c +44 -9
  7. data/ext/rugged/rugged_diff.c +3 -14
  8. data/ext/rugged/rugged_diff_hunk.c +1 -3
  9. data/ext/rugged/rugged_index.c +1 -5
  10. data/ext/rugged/rugged_note.c +1 -4
  11. data/ext/rugged/rugged_patch.c +1 -4
  12. data/ext/rugged/rugged_reference_collection.c +1 -7
  13. data/ext/rugged/rugged_remote.c +5 -8
  14. data/ext/rugged/rugged_remote_collection.c +1 -6
  15. data/ext/rugged/rugged_repo.c +16 -48
  16. data/ext/rugged/rugged_revwalk.c +7 -16
  17. data/ext/rugged/rugged_settings.c +28 -0
  18. data/ext/rugged/rugged_submodule_collection.c +3 -4
  19. data/ext/rugged/rugged_tag_collection.c +1 -5
  20. data/ext/rugged/rugged_tree.c +2 -3
  21. data/lib/rugged/repository.rb +43 -0
  22. data/lib/rugged/version.rb +1 -1
  23. data/vendor/libgit2/AUTHORS +1 -0
  24. data/vendor/libgit2/CMakeLists.txt +61 -510
  25. data/vendor/libgit2/cmake/Modules/EnableWarnings.cmake +14 -0
  26. data/vendor/libgit2/cmake/Modules/FindCoreFoundation.cmake +25 -8
  27. data/vendor/libgit2/cmake/Modules/FindSecurity.cmake +27 -8
  28. data/vendor/libgit2/cmake/Modules/FindStatNsec.cmake +20 -0
  29. data/vendor/libgit2/cmake/Modules/IdeSplitSources.cmake +22 -0
  30. data/vendor/libgit2/deps/http-parser/CMakeLists.txt +3 -0
  31. data/vendor/libgit2/deps/regex/CMakeLists.txt +2 -0
  32. data/vendor/libgit2/deps/winhttp/CMakeLists.txt +26 -0
  33. data/vendor/libgit2/deps/zlib/CMakeLists.txt +4 -0
  34. data/vendor/libgit2/include/git2/config.h +29 -2
  35. data/vendor/libgit2/include/git2/describe.h +1 -1
  36. data/vendor/libgit2/include/git2/diff.h +59 -8
  37. data/vendor/libgit2/include/git2/graph.h +3 -0
  38. data/vendor/libgit2/include/git2/merge.h +6 -0
  39. data/vendor/libgit2/include/git2/message.h +43 -3
  40. data/vendor/libgit2/include/git2/notes.h +89 -0
  41. data/vendor/libgit2/include/git2/odb.h +8 -1
  42. data/vendor/libgit2/include/git2/patch.h +2 -2
  43. data/vendor/libgit2/include/git2/pathspec.h +35 -18
  44. data/vendor/libgit2/include/git2/refs.h +3 -0
  45. data/vendor/libgit2/include/git2/remote.h +34 -4
  46. data/vendor/libgit2/include/git2/repository.h +6 -6
  47. data/vendor/libgit2/include/git2/reset.h +4 -4
  48. data/vendor/libgit2/include/git2/status.h +4 -0
  49. data/vendor/libgit2/include/git2/sys/config.h +4 -1
  50. data/vendor/libgit2/include/git2/sys/odb_backend.h +2 -1
  51. data/vendor/libgit2/include/git2/tree.h +4 -3
  52. data/vendor/libgit2/include/git2/types.h +1 -0
  53. data/vendor/libgit2/include/git2/version.h +4 -4
  54. data/vendor/libgit2/include/git2/worktree.h +1 -1
  55. data/vendor/libgit2/src/CMakeLists.txt +463 -0
  56. data/vendor/libgit2/src/annotated_commit.c +1 -1
  57. data/vendor/libgit2/src/annotated_commit.h +2 -0
  58. data/vendor/libgit2/src/apply.c +2 -1
  59. data/vendor/libgit2/src/apply.h +2 -0
  60. data/vendor/libgit2/src/attr.c +24 -4
  61. data/vendor/libgit2/src/attr.h +2 -0
  62. data/vendor/libgit2/src/attr_file.c +9 -2
  63. data/vendor/libgit2/src/attr_file.h +2 -0
  64. data/vendor/libgit2/src/attrcache.c +9 -1
  65. data/vendor/libgit2/src/attrcache.h +2 -0
  66. data/vendor/libgit2/src/blame.c +1 -0
  67. data/vendor/libgit2/src/blame.h +2 -1
  68. data/vendor/libgit2/src/blame_git.c +1 -0
  69. data/vendor/libgit2/src/blame_git.h +2 -0
  70. data/vendor/libgit2/src/blob.c +2 -2
  71. data/vendor/libgit2/src/blob.h +2 -0
  72. data/vendor/libgit2/src/branch.c +8 -1
  73. data/vendor/libgit2/src/branch.h +2 -0
  74. data/vendor/libgit2/src/buf_text.c +7 -7
  75. data/vendor/libgit2/src/buf_text.h +3 -3
  76. data/vendor/libgit2/src/buffer.c +31 -1
  77. data/vendor/libgit2/src/buffer.h +3 -0
  78. data/vendor/libgit2/src/cache.c +2 -2
  79. data/vendor/libgit2/src/cache.h +2 -0
  80. data/vendor/libgit2/src/cc-compat.h +3 -3
  81. data/vendor/libgit2/src/checkout.c +30 -19
  82. data/vendor/libgit2/src/checkout.h +2 -0
  83. data/vendor/libgit2/src/cherrypick.c +1 -0
  84. data/vendor/libgit2/src/clone.c +2 -1
  85. data/vendor/libgit2/src/clone.h +4 -0
  86. data/vendor/libgit2/src/commit.c +2 -1
  87. data/vendor/libgit2/src/commit.h +2 -0
  88. data/vendor/libgit2/src/commit_list.c +1 -1
  89. data/vendor/libgit2/src/commit_list.h +2 -0
  90. data/vendor/libgit2/src/common.h +11 -5
  91. data/vendor/libgit2/src/config.c +12 -10
  92. data/vendor/libgit2/src/config.h +2 -0
  93. data/vendor/libgit2/src/config_cache.c +1 -0
  94. data/vendor/libgit2/src/config_file.c +287 -786
  95. data/vendor/libgit2/src/config_file.h +4 -3
  96. data/vendor/libgit2/src/config_parse.c +525 -0
  97. data/vendor/libgit2/src/config_parse.h +64 -0
  98. data/vendor/libgit2/src/crlf.c +2 -1
  99. data/vendor/libgit2/src/delta.c +28 -30
  100. data/vendor/libgit2/src/delta.h +1 -0
  101. data/vendor/libgit2/src/describe.c +3 -1
  102. data/vendor/libgit2/src/diff.c +148 -2
  103. data/vendor/libgit2/src/diff.h +3 -1
  104. data/vendor/libgit2/src/diff_driver.c +12 -9
  105. data/vendor/libgit2/src/diff_driver.h +4 -1
  106. data/vendor/libgit2/src/diff_file.c +7 -4
  107. data/vendor/libgit2/src/diff_file.h +1 -0
  108. data/vendor/libgit2/src/diff_generate.c +6 -3
  109. data/vendor/libgit2/src/diff_generate.h +6 -1
  110. data/vendor/libgit2/src/diff_parse.c +5 -4
  111. data/vendor/libgit2/src/diff_parse.h +2 -0
  112. data/vendor/libgit2/src/diff_print.c +2 -0
  113. data/vendor/libgit2/src/diff_stats.c +2 -0
  114. data/vendor/libgit2/src/diff_tform.c +2 -1
  115. data/vendor/libgit2/src/diff_tform.h +4 -1
  116. data/vendor/libgit2/src/diff_xdiff.c +5 -2
  117. data/vendor/libgit2/src/diff_xdiff.h +2 -0
  118. data/vendor/libgit2/src/errors.c +2 -0
  119. data/vendor/libgit2/src/features.h.in +36 -0
  120. data/vendor/libgit2/src/fetch.c +2 -2
  121. data/vendor/libgit2/src/fetch.h +4 -0
  122. data/vendor/libgit2/src/fetchhead.c +3 -3
  123. data/vendor/libgit2/src/fetchhead.h +3 -0
  124. data/vendor/libgit2/src/filebuf.c +2 -1
  125. data/vendor/libgit2/src/filebuf.h +2 -0
  126. data/vendor/libgit2/src/fileops.c +12 -1
  127. data/vendor/libgit2/src/fileops.h +7 -1
  128. data/vendor/libgit2/src/filter.c +2 -1
  129. data/vendor/libgit2/src/filter.h +1 -0
  130. data/vendor/libgit2/src/fnmatch.c +2 -2
  131. data/vendor/libgit2/src/fnmatch.h +3 -4
  132. data/vendor/libgit2/src/global.c +4 -3
  133. data/vendor/libgit2/src/global.h +1 -5
  134. data/vendor/libgit2/src/graph.c +2 -0
  135. data/vendor/libgit2/src/hash.c +0 -1
  136. data/vendor/libgit2/src/hash.h +3 -1
  137. data/vendor/libgit2/src/hash/hash_collisiondetect.h +3 -3
  138. data/vendor/libgit2/src/hash/hash_common_crypto.h +18 -5
  139. data/vendor/libgit2/src/hash/hash_generic.c +2 -2
  140. data/vendor/libgit2/src/hash/hash_generic.h +5 -3
  141. data/vendor/libgit2/src/hash/hash_openssl.h +3 -3
  142. data/vendor/libgit2/src/hash/hash_win32.c +57 -14
  143. data/vendor/libgit2/src/hash/hash_win32.h +4 -3
  144. data/vendor/libgit2/src/hashsig.c +3 -0
  145. data/vendor/libgit2/src/ident.c +2 -0
  146. data/vendor/libgit2/src/idxmap.h +2 -1
  147. data/vendor/libgit2/src/ignore.c +14 -2
  148. data/vendor/libgit2/src/ignore.h +2 -0
  149. data/vendor/libgit2/src/index.c +20 -40
  150. data/vendor/libgit2/src/index.h +2 -0
  151. data/vendor/libgit2/src/indexer.c +13 -5
  152. data/vendor/libgit2/src/indexer.h +5 -1
  153. data/vendor/libgit2/src/integer.h +1 -1
  154. data/vendor/libgit2/src/iterator.c +44 -3
  155. data/vendor/libgit2/src/iterator.h +3 -0
  156. data/vendor/libgit2/src/map.h +1 -1
  157. data/vendor/libgit2/src/merge.c +155 -33
  158. data/vendor/libgit2/src/merge.h +2 -0
  159. data/vendor/libgit2/src/merge_driver.c +2 -2
  160. data/vendor/libgit2/src/merge_driver.h +2 -0
  161. data/vendor/libgit2/src/merge_file.c +3 -0
  162. data/vendor/libgit2/src/message.h +3 -1
  163. data/vendor/libgit2/src/mwindow.c +1 -1
  164. data/vendor/libgit2/src/mwindow.h +2 -0
  165. data/vendor/libgit2/src/netops.c +75 -62
  166. data/vendor/libgit2/src/netops.h +2 -1
  167. data/vendor/libgit2/src/notes.c +164 -48
  168. data/vendor/libgit2/src/notes.h +1 -1
  169. data/vendor/libgit2/src/object.c +14 -3
  170. data/vendor/libgit2/src/object.h +4 -0
  171. data/vendor/libgit2/src/object_api.c +3 -2
  172. data/vendor/libgit2/src/odb.c +104 -38
  173. data/vendor/libgit2/src/odb.h +3 -1
  174. data/vendor/libgit2/src/odb_loose.c +414 -267
  175. data/vendor/libgit2/src/odb_mempack.c +1 -0
  176. data/vendor/libgit2/src/odb_pack.c +2 -1
  177. data/vendor/libgit2/src/offmap.h +1 -0
  178. data/vendor/libgit2/src/oid.c +2 -1
  179. data/vendor/libgit2/src/oid.h +3 -8
  180. data/vendor/libgit2/src/oidarray.c +2 -1
  181. data/vendor/libgit2/src/oidarray.h +1 -0
  182. data/vendor/libgit2/src/oidmap.h +1 -0
  183. data/vendor/libgit2/src/pack-objects.c +5 -1
  184. data/vendor/libgit2/src/pack-objects.h +1 -1
  185. data/vendor/libgit2/src/pack.c +2 -6
  186. data/vendor/libgit2/src/pack.h +2 -1
  187. data/vendor/libgit2/src/parse.c +121 -0
  188. data/vendor/libgit2/src/parse.h +61 -0
  189. data/vendor/libgit2/src/patch.c +9 -2
  190. data/vendor/libgit2/src/patch.h +2 -0
  191. data/vendor/libgit2/src/patch_generate.c +6 -5
  192. data/vendor/libgit2/src/patch_generate.h +1 -0
  193. data/vendor/libgit2/src/patch_parse.c +265 -276
  194. data/vendor/libgit2/src/patch_parse.h +6 -11
  195. data/vendor/libgit2/src/path.c +24 -181
  196. data/vendor/libgit2/src/path.h +14 -73
  197. data/vendor/libgit2/src/pathspec.c +2 -1
  198. data/vendor/libgit2/src/pathspec.h +2 -1
  199. data/vendor/libgit2/src/pool.c +8 -0
  200. data/vendor/libgit2/src/pool.h +1 -0
  201. data/vendor/libgit2/src/posix.c +2 -1
  202. data/vendor/libgit2/src/posix.h +1 -0
  203. data/vendor/libgit2/src/pqueue.c +1 -0
  204. data/vendor/libgit2/src/pqueue.h +2 -0
  205. data/vendor/libgit2/src/proxy.c +2 -1
  206. data/vendor/libgit2/src/proxy.h +3 -1
  207. data/vendor/libgit2/src/push.c +4 -171
  208. data/vendor/libgit2/src/push.h +2 -0
  209. data/vendor/libgit2/src/rebase.c +1 -0
  210. data/vendor/libgit2/src/refdb.c +2 -3
  211. data/vendor/libgit2/src/refdb.h +2 -0
  212. data/vendor/libgit2/src/refdb_fs.c +5 -3
  213. data/vendor/libgit2/src/refdb_fs.h +4 -0
  214. data/vendor/libgit2/src/reflog.c +1 -0
  215. data/vendor/libgit2/src/reflog.h +2 -1
  216. data/vendor/libgit2/src/refs.c +1 -0
  217. data/vendor/libgit2/src/refs.h +2 -1
  218. data/vendor/libgit2/src/refspec.c +2 -2
  219. data/vendor/libgit2/src/refspec.h +2 -0
  220. data/vendor/libgit2/src/remote.c +56 -10
  221. data/vendor/libgit2/src/remote.h +2 -0
  222. data/vendor/libgit2/src/repository.c +16 -14
  223. data/vendor/libgit2/src/repository.h +2 -0
  224. data/vendor/libgit2/src/reset.c +6 -5
  225. data/vendor/libgit2/src/revert.c +1 -0
  226. data/vendor/libgit2/src/revparse.c +3 -5
  227. data/vendor/libgit2/src/revwalk.c +2 -2
  228. data/vendor/libgit2/src/revwalk.h +2 -0
  229. data/vendor/libgit2/src/settings.c +6 -8
  230. data/vendor/libgit2/src/sha1_lookup.c +2 -216
  231. data/vendor/libgit2/src/sha1_lookup.h +2 -6
  232. data/vendor/libgit2/src/signature.c +8 -3
  233. data/vendor/libgit2/src/signature.h +2 -0
  234. data/vendor/libgit2/src/sortedcache.c +7 -0
  235. data/vendor/libgit2/src/sortedcache.h +2 -0
  236. data/vendor/libgit2/src/stash.c +1 -0
  237. data/vendor/libgit2/src/status.c +14 -9
  238. data/vendor/libgit2/src/status.h +2 -0
  239. data/vendor/libgit2/src/{curl_stream.c → streams/curl.c} +2 -0
  240. data/vendor/libgit2/src/{curl_stream.h → streams/curl.h} +4 -2
  241. data/vendor/libgit2/src/{openssl_stream.c → streams/openssl.c} +47 -18
  242. data/vendor/libgit2/src/{openssl_stream.h → streams/openssl.h} +6 -2
  243. data/vendor/libgit2/src/{socket_stream.c → streams/socket.c} +2 -2
  244. data/vendor/libgit2/src/{socket_stream.h → streams/socket.h} +4 -2
  245. data/vendor/libgit2/src/{stransport_stream.c → streams/stransport.c} +4 -2
  246. data/vendor/libgit2/src/{stransport_stream.h → streams/stransport.h} +4 -2
  247. data/vendor/libgit2/src/{tls_stream.c → streams/tls.c} +4 -3
  248. data/vendor/libgit2/src/{tls_stream.h → streams/tls.h} +4 -2
  249. data/vendor/libgit2/src/submodule.c +28 -80
  250. data/vendor/libgit2/src/submodule.h +2 -13
  251. data/vendor/libgit2/src/sysdir.c +75 -8
  252. data/vendor/libgit2/src/sysdir.h +2 -1
  253. data/vendor/libgit2/src/tag.c +2 -2
  254. data/vendor/libgit2/src/tag.h +2 -0
  255. data/vendor/libgit2/src/thread-utils.c +1 -0
  256. data/vendor/libgit2/src/thread-utils.h +1 -1
  257. data/vendor/libgit2/src/trace.c +2 -2
  258. data/vendor/libgit2/src/trace.h +2 -0
  259. data/vendor/libgit2/src/trailer.c +416 -0
  260. data/vendor/libgit2/src/transaction.c +2 -1
  261. data/vendor/libgit2/src/transport.c +2 -0
  262. data/vendor/libgit2/src/transports/auth.c +2 -1
  263. data/vendor/libgit2/src/transports/auth.h +4 -3
  264. data/vendor/libgit2/src/transports/auth_negotiate.c +2 -1
  265. data/vendor/libgit2/src/transports/auth_negotiate.h +3 -3
  266. data/vendor/libgit2/src/transports/cred.c +2 -0
  267. data/vendor/libgit2/src/transports/cred.h +4 -2
  268. data/vendor/libgit2/src/transports/cred_helpers.c +1 -0
  269. data/vendor/libgit2/src/transports/git.c +3 -1
  270. data/vendor/libgit2/src/transports/http.c +10 -14
  271. data/vendor/libgit2/src/transports/http.h +23 -0
  272. data/vendor/libgit2/src/transports/local.c +23 -5
  273. data/vendor/libgit2/src/transports/smart.c +3 -1
  274. data/vendor/libgit2/src/transports/smart.h +23 -16
  275. data/vendor/libgit2/src/transports/smart_pkt.c +114 -130
  276. data/vendor/libgit2/src/transports/smart_protocol.c +26 -22
  277. data/vendor/libgit2/src/transports/ssh.c +12 -7
  278. data/vendor/libgit2/src/transports/ssh.h +4 -2
  279. data/vendor/libgit2/src/transports/winhttp.c +19 -21
  280. data/vendor/libgit2/src/tree-cache.c +1 -0
  281. data/vendor/libgit2/src/tree-cache.h +1 -0
  282. data/vendor/libgit2/src/tree.c +20 -14
  283. data/vendor/libgit2/src/tree.h +2 -0
  284. data/vendor/libgit2/src/tsort.c +0 -1
  285. data/vendor/libgit2/src/unix/map.c +4 -1
  286. data/vendor/libgit2/src/unix/posix.h +8 -4
  287. data/vendor/libgit2/src/unix/pthread.h +1 -1
  288. data/vendor/libgit2/src/unix/realpath.c +4 -1
  289. data/vendor/libgit2/src/util.c +6 -5
  290. data/vendor/libgit2/src/util.h +39 -111
  291. data/vendor/libgit2/src/varint.c +0 -1
  292. data/vendor/libgit2/src/varint.h +2 -0
  293. data/vendor/libgit2/src/vector.c +1 -1
  294. data/vendor/libgit2/src/win32/dir.c +3 -0
  295. data/vendor/libgit2/src/win32/dir.h +4 -3
  296. data/vendor/libgit2/src/win32/error.c +1 -1
  297. data/vendor/libgit2/src/win32/error.h +4 -2
  298. data/vendor/libgit2/src/win32/findfile.c +2 -1
  299. data/vendor/libgit2/src/win32/findfile.h +4 -2
  300. data/vendor/libgit2/src/win32/map.c +2 -0
  301. data/vendor/libgit2/src/win32/mingw-compat.h +3 -3
  302. data/vendor/libgit2/src/win32/msvc-compat.h +3 -3
  303. data/vendor/libgit2/src/win32/path_w32.c +7 -12
  304. data/vendor/libgit2/src/win32/path_w32.h +3 -2
  305. data/vendor/libgit2/src/win32/posix.h +2 -2
  306. data/vendor/libgit2/src/win32/posix_w32.c +11 -5
  307. data/vendor/libgit2/src/win32/precompiled.h +2 -1
  308. data/vendor/libgit2/src/win32/reparse.h +2 -2
  309. data/vendor/libgit2/src/win32/thread.c +1 -0
  310. data/vendor/libgit2/src/win32/thread.h +2 -2
  311. data/vendor/libgit2/src/win32/utf-conv.c +0 -1
  312. data/vendor/libgit2/src/win32/utf-conv.h +4 -3
  313. data/vendor/libgit2/src/win32/w32_buffer.c +1 -1
  314. data/vendor/libgit2/src/win32/w32_buffer.h +4 -2
  315. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.c +2 -1
  316. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.h +85 -2
  317. data/vendor/libgit2/src/win32/w32_stack.c +2 -1
  318. data/vendor/libgit2/src/win32/w32_stack.h +5 -3
  319. data/vendor/libgit2/src/win32/w32_util.h +4 -2
  320. data/vendor/libgit2/src/win32/win32-compat.h +3 -3
  321. data/vendor/libgit2/src/worktree.c +4 -5
  322. data/vendor/libgit2/src/worktree.h +2 -0
  323. data/vendor/libgit2/src/xdiff/xdiff.h +22 -13
  324. data/vendor/libgit2/src/xdiff/xdiffi.c +523 -81
  325. data/vendor/libgit2/src/xdiff/xdiffi.h +2 -2
  326. data/vendor/libgit2/src/xdiff/xemit.c +63 -39
  327. data/vendor/libgit2/src/xdiff/xemit.h +2 -2
  328. data/vendor/libgit2/src/xdiff/xhistogram.c +0 -1
  329. data/vendor/libgit2/src/xdiff/xinclude.h +3 -2
  330. data/vendor/libgit2/src/xdiff/xmacros.h +2 -2
  331. data/vendor/libgit2/src/xdiff/xmerge.c +80 -20
  332. data/vendor/libgit2/src/xdiff/xpatience.c +41 -9
  333. data/vendor/libgit2/src/xdiff/xprepare.c +2 -2
  334. data/vendor/libgit2/src/xdiff/xprepare.h +2 -2
  335. data/vendor/libgit2/src/xdiff/xtypes.h +2 -2
  336. data/vendor/libgit2/src/xdiff/xutils.c +47 -27
  337. data/vendor/libgit2/src/xdiff/xutils.h +2 -5
  338. data/vendor/libgit2/src/zstream.c +65 -45
  339. data/vendor/libgit2/src/zstream.h +9 -2
  340. metadata +27 -13
  341. data/vendor/libgit2/include/git2/sys/remote.h +0 -16
@@ -7,6 +7,8 @@
7
7
  #ifndef INCLUDE_checkout_h__
8
8
  #define INCLUDE_checkout_h__
9
9
 
10
+ #include "common.h"
11
+
10
12
  #include "git2/checkout.h"
11
13
  #include "iterator.h"
12
14
 
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  #include "common.h"
9
+
9
10
  #include "repository.h"
10
11
  #include "filebuf.h"
11
12
  #include "merge.h"
@@ -5,6 +5,8 @@
5
5
  * a Linking Exception. For full terms see the included COPYING file.
6
6
  */
7
7
 
8
+ #include "clone.h"
9
+
8
10
  #include <assert.h>
9
11
 
10
12
  #include "git2/clone.h"
@@ -16,7 +18,6 @@
16
18
  #include "git2/commit.h"
17
19
  #include "git2/tree.h"
18
20
 
19
- #include "common.h"
20
21
  #include "remote.h"
21
22
  #include "fileops.h"
22
23
  #include "refs.h"
@@ -7,6 +7,10 @@
7
7
  #ifndef INCLUDE_clone_h__
8
8
  #define INCLUDE_clone_h__
9
9
 
10
+ #include "common.h"
11
+
12
+ #include "git2/clone.h"
13
+
10
14
  extern int git_clone__should_clone_local(const char *url, git_clone_local_t local);
11
15
 
12
16
  #endif
@@ -5,13 +5,14 @@
5
5
  * a Linking Exception. For full terms see the included COPYING file.
6
6
  */
7
7
 
8
+ #include "commit.h"
9
+
8
10
  #include "git2/common.h"
9
11
  #include "git2/object.h"
10
12
  #include "git2/repository.h"
11
13
  #include "git2/signature.h"
12
14
  #include "git2/sys/commit.h"
13
15
 
14
- #include "common.h"
15
16
  #include "odb.h"
16
17
  #include "commit.h"
17
18
  #include "signature.h"
@@ -7,6 +7,8 @@
7
7
  #ifndef INCLUDE_commit_h__
8
8
  #define INCLUDE_commit_h__
9
9
 
10
+ #include "common.h"
11
+
10
12
  #include "git2/commit.h"
11
13
  #include "tree.h"
12
14
  #include "repository.h"
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  #include "commit_list.h"
9
- #include "common.h"
9
+
10
10
  #include "revwalk.h"
11
11
  #include "pool.h"
12
12
  #include "odb.h"
@@ -7,6 +7,8 @@
7
7
  #ifndef INCLUDE_commit_list_h__
8
8
  #define INCLUDE_commit_list_h__
9
9
 
10
+ #include "common.h"
11
+
10
12
  #include "git2/oid.h"
11
13
 
12
14
  #define PARENT1 (1 << 0)
@@ -7,6 +7,10 @@
7
7
  #ifndef INCLUDE_common_h__
8
8
  #define INCLUDE_common_h__
9
9
 
10
+ #ifndef LIBGIT2_NO_FEATURES_H
11
+ # include "git2/sys/features.h"
12
+ #endif
13
+
10
14
  #include "git2/common.h"
11
15
  #include "cc-compat.h"
12
16
 
@@ -47,10 +51,6 @@
47
51
  # ifdef GIT_THREADS
48
52
  # include "win32/thread.h"
49
53
  # endif
50
- # if defined(GIT_MSVC_CRTDBG)
51
- # include "win32/w32_stack.h"
52
- # include "win32/w32_crtdbg_stacktrace.h"
53
- # endif
54
54
 
55
55
  #else
56
56
 
@@ -230,6 +230,12 @@ GIT_INLINE(void) git__init_structure(void *structure, size_t len, unsigned int v
230
230
  GIT_ADD_SIZET_OVERFLOW(out, *(out), three) || \
231
231
  GIT_ADD_SIZET_OVERFLOW(out, *(out), four)) { return -1; }
232
232
 
233
+ #define GITERR_CHECK_ALLOC_ADD5(out, one, two, three, four, five) \
234
+ if (GIT_ADD_SIZET_OVERFLOW(out, one, two) || \
235
+ GIT_ADD_SIZET_OVERFLOW(out, *(out), three) || \
236
+ GIT_ADD_SIZET_OVERFLOW(out, *(out), four) || \
237
+ GIT_ADD_SIZET_OVERFLOW(out, *(out), five)) { return -1; }
238
+
233
239
  /** Check for multiplicative overflow, failing if it would occur. */
234
240
  #define GITERR_CHECK_ALLOC_MULTIPLY(out, nelem, elsize) \
235
241
  if (GIT_MULTIPLY_SIZET_OVERFLOW(out, nelem, elsize)) { return -1; }
@@ -238,4 +244,4 @@ GIT_INLINE(void) git__init_structure(void *structure, size_t len, unsigned int v
238
244
 
239
245
  #include "util.h"
240
246
 
241
- #endif /* INCLUDE_common_h__ */
247
+ #endif
@@ -5,9 +5,9 @@
5
5
  * a Linking Exception. For full terms see the included COPYING file.
6
6
  */
7
7
 
8
- #include "common.h"
9
- #include "sysdir.h"
10
8
  #include "config.h"
9
+
10
+ #include "sysdir.h"
11
11
  #include "git2/config.h"
12
12
  #include "git2/sys/config.h"
13
13
  #include "vector.h"
@@ -99,6 +99,7 @@ int git_config_add_file_ondisk(
99
99
  git_config *cfg,
100
100
  const char *path,
101
101
  git_config_level_t level,
102
+ const git_repository *repo,
102
103
  int force)
103
104
  {
104
105
  git_config_backend *file = NULL;
@@ -116,7 +117,7 @@ int git_config_add_file_ondisk(
116
117
  if (git_config_file__ondisk(&file, path) < 0)
117
118
  return -1;
118
119
 
119
- if ((res = git_config_add_backend(cfg, file, level, force)) < 0) {
120
+ if ((res = git_config_add_backend(cfg, file, level, repo, force)) < 0) {
120
121
  /*
121
122
  * free manually; the file is not owned by the config
122
123
  * instance yet and will not be freed on cleanup
@@ -138,7 +139,7 @@ int git_config_open_ondisk(git_config **out, const char *path)
138
139
  if (git_config_new(&config) < 0)
139
140
  return -1;
140
141
 
141
- if ((error = git_config_add_file_ondisk(config, path, GIT_CONFIG_LEVEL_LOCAL, 0)) < 0)
142
+ if ((error = git_config_add_file_ondisk(config, path, GIT_CONFIG_LEVEL_LOCAL, NULL, 0)) < 0)
142
143
  git_config_free(config);
143
144
  else
144
145
  *out = config;
@@ -164,7 +165,7 @@ int git_config_snapshot(git_config **out, git_config *in)
164
165
  if ((error = internal->file->snapshot(&b, internal->file)) < 0)
165
166
  break;
166
167
 
167
- if ((error = git_config_add_backend(config, b, internal->level, 0)) < 0) {
168
+ if ((error = git_config_add_backend(config, b, internal->level, NULL, 0)) < 0) {
168
169
  b->free(b);
169
170
  break;
170
171
  }
@@ -307,6 +308,7 @@ int git_config_add_backend(
307
308
  git_config *cfg,
308
309
  git_config_backend *file,
309
310
  git_config_level_t level,
311
+ const git_repository *repo,
310
312
  int force)
311
313
  {
312
314
  file_internal *internal;
@@ -316,7 +318,7 @@ int git_config_add_backend(
316
318
 
317
319
  GITERR_CHECK_VERSION(file, GIT_CONFIG_BACKEND_VERSION, "git_config_backend");
318
320
 
319
- if ((result = file->open(file, level)) < 0)
321
+ if ((result = file->open(file, level, repo)) < 0)
320
322
  return result;
321
323
 
322
324
  internal = git__malloc(sizeof(file_internal));
@@ -1147,20 +1149,20 @@ int git_config_open_default(git_config **out)
1147
1149
 
1148
1150
  if (!git_config_find_global(&buf) || !git_config__global_location(&buf)) {
1149
1151
  error = git_config_add_file_ondisk(cfg, buf.ptr,
1150
- GIT_CONFIG_LEVEL_GLOBAL, 0);
1152
+ GIT_CONFIG_LEVEL_GLOBAL, NULL, 0);
1151
1153
  }
1152
1154
 
1153
1155
  if (!error && !git_config_find_xdg(&buf))
1154
1156
  error = git_config_add_file_ondisk(cfg, buf.ptr,
1155
- GIT_CONFIG_LEVEL_XDG, 0);
1157
+ GIT_CONFIG_LEVEL_XDG, NULL, 0);
1156
1158
 
1157
1159
  if (!error && !git_config_find_system(&buf))
1158
1160
  error = git_config_add_file_ondisk(cfg, buf.ptr,
1159
- GIT_CONFIG_LEVEL_SYSTEM, 0);
1161
+ GIT_CONFIG_LEVEL_SYSTEM, NULL, 0);
1160
1162
 
1161
1163
  if (!error && !git_config_find_programdata(&buf))
1162
1164
  error = git_config_add_file_ondisk(cfg, buf.ptr,
1163
- GIT_CONFIG_LEVEL_PROGRAMDATA, 0);
1165
+ GIT_CONFIG_LEVEL_PROGRAMDATA, NULL, 0);
1164
1166
 
1165
1167
  git_buf_free(&buf);
1166
1168
 
@@ -7,6 +7,8 @@
7
7
  #ifndef INCLUDE_config_h__
8
8
  #define INCLUDE_config_h__
9
9
 
10
+ #include "common.h"
11
+
10
12
  #include "git2.h"
11
13
  #include "git2/config.h"
12
14
  #include "vector.h"
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  #include "common.h"
9
+
9
10
  #include "fileops.h"
10
11
  #include "repository.h"
11
12
  #include "config.h"
@@ -5,7 +5,8 @@
5
5
  * a Linking Exception. For full terms see the included COPYING file.
6
6
  */
7
7
 
8
- #include "common.h"
8
+ #include "config_file.h"
9
+
9
10
  #include "config.h"
10
11
  #include "filebuf.h"
11
12
  #include "sysdir.h"
@@ -16,6 +17,7 @@
16
17
  #include "git2/types.h"
17
18
  #include "strmap.h"
18
19
  #include "array.h"
20
+ #include "config_parse.h"
19
21
 
20
22
  #include <ctype.h>
21
23
  #include <sys/types.h>
@@ -74,15 +76,6 @@ typedef struct git_config_file_iter {
74
76
  (iter) && (((tmp) = CVAR_LIST_NEXT(iter) || 1));\
75
77
  (iter) = (tmp))
76
78
 
77
- struct reader {
78
- git_oid checksum;
79
- char *file_path;
80
- git_buf buffer;
81
- char *read_ptr;
82
- int line_number;
83
- int eof;
84
- };
85
-
86
79
  typedef struct {
87
80
  git_atomic refcount;
88
81
  git_strmap *values;
@@ -93,20 +86,20 @@ typedef struct {
93
86
  /* mutex to coordinate accessing the values */
94
87
  git_mutex values_mutex;
95
88
  refcounted_strmap *values;
89
+ const git_repository *repo;
90
+ git_config_level_t level;
96
91
  } diskfile_header;
97
92
 
98
93
  typedef struct {
99
94
  diskfile_header header;
100
95
 
101
- git_config_level_t level;
102
-
103
- git_array_t(struct reader) readers;
96
+ git_array_t(git_config_parser) readers;
104
97
 
105
98
  bool locked;
106
99
  git_filebuf locked_buf;
107
100
  git_buf locked_content;
108
101
 
109
- char *file_path;
102
+ struct config_file file;
110
103
  } diskfile_backend;
111
104
 
112
105
  typedef struct {
@@ -115,19 +108,13 @@ typedef struct {
115
108
  diskfile_backend *snapshot_from;
116
109
  } diskfile_readonly_backend;
117
110
 
118
- static int config_read(git_strmap *values, diskfile_backend *cfg_file, struct reader *reader, git_config_level_t level, int depth);
119
- static int config_write(diskfile_backend *cfg, const char *key, const regex_t *preg, const char *value);
111
+ static int config_read(git_strmap *values, const git_repository *repo, git_config_file *file, git_config_level_t level, int depth);
112
+ static int config_write(diskfile_backend *cfg, const char *orig_key, const char *key, const regex_t *preg, const char *value);
120
113
  static char *escape_value(const char *ptr);
121
114
 
122
115
  int git_config_file__snapshot(git_config_backend **out, diskfile_backend *in);
123
116
  static int config_snapshot(git_config_backend **out, git_config_backend *in);
124
117
 
125
- static void set_parse_error(struct reader *reader, int col, const char *error_str)
126
- {
127
- giterr_set(GITERR_CONFIG, "failed to parse config file: %s (in %s:%d, column %d)",
128
- error_str, reader->file_path, reader->line_number, col);
129
- }
130
-
131
118
  static int config_error_readonly(void)
132
119
  {
133
120
  giterr_set(GITERR_CONFIG, "this backend is read-only");
@@ -261,123 +248,131 @@ static int refcounted_strmap_alloc(refcounted_strmap **out)
261
248
  return error;
262
249
  }
263
250
 
264
- static int config_open(git_config_backend *cfg, git_config_level_t level)
251
+ static void config_file_clear(struct config_file *file)
252
+ {
253
+ struct config_file *include;
254
+ uint32_t i;
255
+
256
+ if (file == NULL)
257
+ return;
258
+
259
+ git_array_foreach(file->includes, i, include) {
260
+ config_file_clear(include);
261
+ }
262
+ git_array_clear(file->includes);
263
+
264
+ git__free(file->path);
265
+ }
266
+
267
+ static int config_open(git_config_backend *cfg, git_config_level_t level, const git_repository *repo)
265
268
  {
266
269
  int res;
267
- struct reader *reader;
268
270
  diskfile_backend *b = (diskfile_backend *)cfg;
269
271
 
270
- b->level = level;
272
+ b->header.level = level;
273
+ b->header.repo = repo;
271
274
 
272
275
  if ((res = refcounted_strmap_alloc(&b->header.values)) < 0)
273
276
  return res;
274
277
 
275
- git_array_init(b->readers);
276
- reader = git_array_alloc(b->readers);
277
- if (!reader) {
278
- refcounted_strmap_free(b->header.values);
279
- return -1;
280
- }
281
- memset(reader, 0, sizeof(struct reader));
282
-
283
- reader->file_path = git__strdup(b->file_path);
284
- GITERR_CHECK_ALLOC(reader->file_path);
285
-
286
- git_buf_init(&reader->buffer, 0);
287
- res = git_futils_readbuffer_updated(
288
- &reader->buffer, b->file_path, &reader->checksum, NULL);
289
-
290
- /* It's fine if the file doesn't exist */
291
- if (res == GIT_ENOTFOUND)
278
+ if (!git_path_exists(b->file.path))
292
279
  return 0;
293
280
 
294
- if (res < 0 || (res = config_read(b->header.values->values, b, reader, level, 0)) < 0) {
281
+ if (res < 0 || (res = config_read(b->header.values->values, repo, &b->file, level, 0)) < 0) {
295
282
  refcounted_strmap_free(b->header.values);
296
283
  b->header.values = NULL;
297
284
  }
298
285
 
299
- reader = git_array_get(b->readers, 0);
300
- git_buf_free(&reader->buffer);
301
-
302
286
  return res;
303
287
  }
304
288
 
305
- /* The meat of the refresh, as we want to use it in different places */
306
- static int config__refresh(git_config_backend *cfg)
289
+ static int config_is_modified(int *modified, struct config_file *file)
307
290
  {
308
- refcounted_strmap *values = NULL, *tmp;
309
- diskfile_backend *b = (diskfile_backend *)cfg;
310
- struct reader *reader = NULL;
291
+ git_config_file *include;
292
+ git_buf buf = GIT_BUF_INIT;
293
+ git_oid hash;
294
+ uint32_t i;
311
295
  int error = 0;
312
296
 
313
- if ((error = refcounted_strmap_alloc(&values)) < 0)
314
- goto out;
297
+ *modified = 0;
315
298
 
316
- reader = git_array_get(b->readers, git_array_size(b->readers) - 1);
317
- GITERR_CHECK_ALLOC(reader);
299
+ if ((error = git_futils_readbuffer(&buf, file->path)) < 0)
300
+ goto out;
318
301
 
319
- if ((error = config_read(values->values, b, reader, b->level, 0)) < 0)
302
+ if ((error = git_hash_buf(&hash, buf.ptr, buf.size)) < 0)
320
303
  goto out;
321
304
 
322
- if ((error = git_mutex_lock(&b->header.values_mutex)) < 0) {
323
- giterr_set(GITERR_OS, "failed to lock config backend");
305
+ if (!git_oid_equal(&hash, &file->checksum)) {
306
+ *modified = 1;
324
307
  goto out;
325
308
  }
326
309
 
327
- tmp = b->header.values;
328
- b->header.values = values;
329
- values = tmp;
330
-
331
- git_mutex_unlock(&b->header.values_mutex);
310
+ git_array_foreach(file->includes, i, include) {
311
+ if ((error = config_is_modified(modified, include)) < 0 || *modified)
312
+ goto out;
313
+ }
332
314
 
333
315
  out:
334
- refcounted_strmap_free(values);
335
- if (reader)
336
- git_buf_free(&reader->buffer);
316
+ git_buf_free(&buf);
317
+
337
318
  return error;
338
319
  }
339
320
 
340
321
  static int config_refresh(git_config_backend *cfg)
341
322
  {
342
- int error = 0, updated = 0, any_updated = 0;
343
323
  diskfile_backend *b = (diskfile_backend *)cfg;
344
- struct reader *reader = NULL;
324
+ refcounted_strmap *values = NULL, *tmp;
325
+ git_config_file *include;
326
+ int error, modified;
345
327
  uint32_t i;
346
328
 
347
- for (i = 0; i < git_array_size(b->readers); i++) {
348
- reader = git_array_get(b->readers, i);
349
- error = git_futils_readbuffer_updated(
350
- &reader->buffer, reader->file_path,
351
- &reader->checksum, &updated);
329
+ if (b->header.parent.readonly)
330
+ return config_error_readonly();
331
+
332
+ error = config_is_modified(&modified, &b->file);
333
+ if (error < 0 && error != GIT_ENOTFOUND)
334
+ goto out;
335
+
336
+ if (!modified)
337
+ return 0;
352
338
 
353
- if (error < 0 && error != GIT_ENOTFOUND)
354
- return error;
339
+ if ((error = refcounted_strmap_alloc(&values)) < 0)
340
+ goto out;
341
+
342
+ /* Reparse the current configuration */
343
+ git_array_foreach(b->file.includes, i, include) {
344
+ config_file_clear(include);
345
+ }
346
+ git_array_clear(b->file.includes);
347
+
348
+ if ((error = config_read(values->values, b->header.repo, &b->file, b->header.level, 0)) < 0)
349
+ goto out;
355
350
 
356
- if (updated)
357
- any_updated = 1;
351
+ if ((error = git_mutex_lock(&b->header.values_mutex)) < 0) {
352
+ giterr_set(GITERR_OS, "failed to lock config backend");
353
+ goto out;
358
354
  }
359
355
 
360
- if (!any_updated)
361
- return (error == GIT_ENOTFOUND) ? 0 : error;
356
+ tmp = b->header.values;
357
+ b->header.values = values;
358
+ values = tmp;
359
+
360
+ git_mutex_unlock(&b->header.values_mutex);
361
+
362
+ out:
363
+ refcounted_strmap_free(values);
362
364
 
363
- return config__refresh(cfg);
365
+ return (error == GIT_ENOTFOUND) ? 0 : error;
364
366
  }
365
367
 
366
368
  static void backend_free(git_config_backend *_backend)
367
369
  {
368
370
  diskfile_backend *backend = (diskfile_backend *)_backend;
369
- uint32_t i;
370
371
 
371
372
  if (backend == NULL)
372
373
  return;
373
374
 
374
- for (i = 0; i < git_array_size(backend->readers); i++) {
375
- struct reader *r = git_array_get(backend->readers, i);
376
- git__free(r->file_path);
377
- }
378
- git_array_clear(backend->readers);
379
-
380
- git__free(backend->file_path);
375
+ config_file_clear(&backend->file);
381
376
  refcounted_strmap_free(backend->header.values);
382
377
  git_mutex_free(&backend->header.values_mutex);
383
378
  git__free(backend);
@@ -424,13 +419,13 @@ static int config_iterator_new(
424
419
  diskfile_header *h;
425
420
  git_config_file_iter *it;
426
421
  git_config_backend *snapshot;
427
- diskfile_backend *b = (diskfile_backend *) backend;
422
+ diskfile_header *bh = (diskfile_header *) backend;
428
423
  int error;
429
424
 
430
425
  if ((error = config_snapshot(&snapshot, backend)) < 0)
431
426
  return error;
432
427
 
433
- if ((error = snapshot->open(snapshot, b->level)) < 0)
428
+ if ((error = snapshot->open(snapshot, bh->level, bh->repo)) < 0)
434
429
  return error;
435
430
 
436
431
  it = git__calloc(1, sizeof(git_config_file_iter));
@@ -482,6 +477,12 @@ static int config_set(git_config_backend *cfg, const char *name, const char *val
482
477
  goto out;
483
478
  }
484
479
 
480
+ if (existing->included) {
481
+ giterr_set(GITERR_CONFIG, "modifying included variable is not supported");
482
+ ret = -1;
483
+ goto out;
484
+ }
485
+
485
486
  /* don't update if old and new values already match */
486
487
  if ((!existing->entry->value && !value) ||
487
488
  (existing->entry->value && value &&
@@ -498,7 +499,7 @@ static int config_set(git_config_backend *cfg, const char *name, const char *val
498
499
  GITERR_CHECK_ALLOC(esc_value);
499
500
  }
500
501
 
501
- if ((ret = config_write(b, key, NULL, esc_value)) < 0)
502
+ if ((ret = config_write(b, name, key, NULL, esc_value)) < 0)
502
503
  goto out;
503
504
 
504
505
  ret = config_refresh(cfg);
@@ -576,7 +577,7 @@ static int config_set_multivar(
576
577
  }
577
578
 
578
579
  /* If we do have it, set call config_write() and reload */
579
- if ((result = config_write(b, key, &preg, value)) < 0)
580
+ if ((result = config_write(b, name, key, &preg, value)) < 0)
580
581
  goto out;
581
582
 
582
583
  result = config_refresh(cfg);
@@ -616,12 +617,17 @@ static int config_delete(git_config_backend *cfg, const char *name)
616
617
  var = git_strmap_value_at(values, pos);
617
618
  refcounted_strmap_free(map);
618
619
 
620
+ if (var->included) {
621
+ giterr_set(GITERR_CONFIG, "cannot delete included variable");
622
+ return -1;
623
+ }
624
+
619
625
  if (var->next != NULL) {
620
626
  giterr_set(GITERR_CONFIG, "cannot delete multivar with a single delete");
621
627
  return -1;
622
628
  }
623
629
 
624
- if ((result = config_write(b, var->entry->name, NULL, NULL)) < 0)
630
+ if ((result = config_write(b, name, var->entry->name, NULL, NULL)) < 0)
625
631
  return result;
626
632
 
627
633
  return config_refresh(cfg);
@@ -662,7 +668,7 @@ static int config_delete_multivar(git_config_backend *cfg, const char *name, con
662
668
  goto out;
663
669
  }
664
670
 
665
- if ((result = config_write(b, key, &preg, NULL)) < 0)
671
+ if ((result = config_write(b, name, key, &preg, NULL)) < 0)
666
672
  goto out;
667
673
 
668
674
  result = config_refresh(cfg);
@@ -685,10 +691,10 @@ static int config_lock(git_config_backend *_cfg)
685
691
  diskfile_backend *cfg = (diskfile_backend *) _cfg;
686
692
  int error;
687
693
 
688
- if ((error = git_filebuf_open(&cfg->locked_buf, cfg->file_path, 0, GIT_CONFIG_FILE_MODE)) < 0)
694
+ if ((error = git_filebuf_open(&cfg->locked_buf, cfg->file.path, 0, GIT_CONFIG_FILE_MODE)) < 0)
689
695
  return error;
690
696
 
691
- error = git_futils_readbuffer(&cfg->locked_content, cfg->file_path);
697
+ error = git_futils_readbuffer(&cfg->locked_content, cfg->file.path);
692
698
  if (error < 0 && error != GIT_ENOTFOUND) {
693
699
  git_filebuf_cleanup(&cfg->locked_buf);
694
700
  return error;
@@ -726,8 +732,9 @@ int git_config_file__ondisk(git_config_backend **out, const char *path)
726
732
  backend->header.parent.version = GIT_CONFIG_BACKEND_VERSION;
727
733
  git_mutex_init(&backend->header.values_mutex);
728
734
 
729
- backend->file_path = git__strdup(path);
730
- GITERR_CHECK_ALLOC(backend->file_path);
735
+ backend->file.path = git__strdup(path);
736
+ GITERR_CHECK_ALLOC(backend->file.path);
737
+ git_array_init(backend->file.includes);
731
738
 
732
739
  backend->header.parent.open = config_open;
733
740
  backend->header.parent.get = config_get;
@@ -810,7 +817,7 @@ static void backend_readonly_free(git_config_backend *_backend)
810
817
  git__free(backend);
811
818
  }
812
819
 
813
- static int config_readonly_open(git_config_backend *cfg, git_config_level_t level)
820
+ static int config_readonly_open(git_config_backend *cfg, git_config_level_t level, const git_repository *repo)
814
821
  {
815
822
  diskfile_readonly_backend *b = (diskfile_readonly_backend *) cfg;
816
823
  diskfile_backend *src = b->snapshot_from;
@@ -821,8 +828,9 @@ static int config_readonly_open(git_config_backend *cfg, git_config_level_t leve
821
828
  if (!src_header->parent.readonly && (error = config_refresh(&src_header->parent)) < 0)
822
829
  return error;
823
830
 
824
- /* We're just copying data, don't care about the level */
831
+ /* We're just copying data, don't care about the level or repo*/
825
832
  GIT_UNUSED(level);
833
+ GIT_UNUSED(repo);
826
834
 
827
835
  if ((src_map = refcounted_strmap_take(src_header)) == NULL)
828
836
  return -1;
@@ -861,397 +869,6 @@ int git_config_file__snapshot(git_config_backend **out, diskfile_backend *in)
861
869
  return 0;
862
870
  }
863
871
 
864
- static int reader_getchar_raw(struct reader *reader)
865
- {
866
- int c;
867
-
868
- c = *reader->read_ptr++;
869
-
870
- /*
871
- Win 32 line breaks: if we find a \r\n sequence,
872
- return only the \n as a newline
873
- */
874
- if (c == '\r' && *reader->read_ptr == '\n') {
875
- reader->read_ptr++;
876
- c = '\n';
877
- }
878
-
879
- if (c == '\n')
880
- reader->line_number++;
881
-
882
- if (c == 0) {
883
- reader->eof = 1;
884
- c = '\0';
885
- }
886
-
887
- return c;
888
- }
889
-
890
- #define SKIP_WHITESPACE (1 << 1)
891
- #define SKIP_COMMENTS (1 << 2)
892
-
893
- static int reader_getchar(struct reader *reader, int flags)
894
- {
895
- const int skip_whitespace = (flags & SKIP_WHITESPACE);
896
- const int skip_comments = (flags & SKIP_COMMENTS);
897
- int c;
898
-
899
- assert(reader->read_ptr);
900
-
901
- do {
902
- c = reader_getchar_raw(reader);
903
- } while (c != '\n' && c != '\0' && skip_whitespace && git__isspace(c));
904
-
905
- if (skip_comments && (c == '#' || c == ';')) {
906
- do {
907
- c = reader_getchar_raw(reader);
908
- } while (c != '\n' && c != '\0');
909
- }
910
-
911
- return c;
912
- }
913
-
914
- /*
915
- * Read the next char, but don't move the reading pointer.
916
- */
917
- static int reader_peek(struct reader *reader, int flags)
918
- {
919
- void *old_read_ptr;
920
- int old_lineno, old_eof;
921
- int ret;
922
-
923
- assert(reader->read_ptr);
924
-
925
- old_read_ptr = reader->read_ptr;
926
- old_lineno = reader->line_number;
927
- old_eof = reader->eof;
928
-
929
- ret = reader_getchar(reader, flags);
930
-
931
- reader->read_ptr = old_read_ptr;
932
- reader->line_number = old_lineno;
933
- reader->eof = old_eof;
934
-
935
- return ret;
936
- }
937
-
938
- /*
939
- * Read and consume a line, returning it in newly-allocated memory.
940
- */
941
- static char *reader_readline(struct reader *reader, bool skip_whitespace)
942
- {
943
- char *line = NULL;
944
- char *line_src, *line_end;
945
- size_t line_len, alloc_len;
946
-
947
- line_src = reader->read_ptr;
948
-
949
- if (skip_whitespace) {
950
- /* Skip empty empty lines */
951
- while (git__isspace(*line_src))
952
- ++line_src;
953
- }
954
-
955
- line_end = strchr(line_src, '\n');
956
-
957
- /* no newline at EOF */
958
- if (line_end == NULL)
959
- line_end = strchr(line_src, 0);
960
-
961
- line_len = line_end - line_src;
962
-
963
- if (GIT_ADD_SIZET_OVERFLOW(&alloc_len, line_len, 1) ||
964
- (line = git__malloc(alloc_len)) == NULL) {
965
- return NULL;
966
- }
967
-
968
- memcpy(line, line_src, line_len);
969
-
970
- do line[line_len] = '\0';
971
- while (line_len-- > 0 && git__isspace(line[line_len]));
972
-
973
- if (*line_end == '\n')
974
- line_end++;
975
-
976
- if (*line_end == '\0')
977
- reader->eof = 1;
978
-
979
- reader->line_number++;
980
- reader->read_ptr = line_end;
981
-
982
- return line;
983
- }
984
-
985
- /*
986
- * Consume a line, without storing it anywhere
987
- */
988
- static void reader_consume_line(struct reader *reader)
989
- {
990
- char *line_start, *line_end;
991
-
992
- line_start = reader->read_ptr;
993
- line_end = strchr(line_start, '\n');
994
- /* No newline at EOF */
995
- if(line_end == NULL){
996
- line_end = strchr(line_start, '\0');
997
- }
998
-
999
- if (*line_end == '\n')
1000
- line_end++;
1001
-
1002
- if (*line_end == '\0')
1003
- reader->eof = 1;
1004
-
1005
- reader->line_number++;
1006
- reader->read_ptr = line_end;
1007
- }
1008
-
1009
- GIT_INLINE(int) config_keychar(int c)
1010
- {
1011
- return isalnum(c) || c == '-';
1012
- }
1013
-
1014
- static int parse_section_header_ext(struct reader *reader, const char *line, const char *base_name, char **section_name)
1015
- {
1016
- int c, rpos;
1017
- char *first_quote, *last_quote;
1018
- git_buf buf = GIT_BUF_INIT;
1019
- size_t quoted_len, alloc_len, base_name_len = strlen(base_name);
1020
-
1021
- /*
1022
- * base_name is what came before the space. We should be at the
1023
- * first quotation mark, except for now, line isn't being kept in
1024
- * sync so we only really use it to calculate the length.
1025
- */
1026
-
1027
- first_quote = strchr(line, '"');
1028
- if (first_quote == NULL) {
1029
- set_parse_error(reader, 0, "Missing quotation marks in section header");
1030
- goto end_error;
1031
- }
1032
-
1033
- last_quote = strrchr(line, '"');
1034
- quoted_len = last_quote - first_quote;
1035
-
1036
- if (quoted_len == 0) {
1037
- set_parse_error(reader, 0, "Missing closing quotation mark in section header");
1038
- goto end_error;
1039
- }
1040
-
1041
- GITERR_CHECK_ALLOC_ADD(&alloc_len, base_name_len, quoted_len);
1042
- GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 2);
1043
-
1044
- if (git_buf_grow(&buf, alloc_len) < 0 ||
1045
- git_buf_printf(&buf, "%s.", base_name) < 0)
1046
- goto end_error;
1047
-
1048
- rpos = 0;
1049
-
1050
- line = first_quote;
1051
- c = line[++rpos];
1052
-
1053
- /*
1054
- * At the end of each iteration, whatever is stored in c will be
1055
- * added to the string. In case of error, jump to out
1056
- */
1057
- do {
1058
-
1059
- switch (c) {
1060
- case 0:
1061
- set_parse_error(reader, 0, "Unexpected end-of-line in section header");
1062
- goto end_error;
1063
-
1064
- case '"':
1065
- goto end_parse;
1066
-
1067
- case '\\':
1068
- c = line[++rpos];
1069
-
1070
- if (c == 0) {
1071
- set_parse_error(reader, rpos, "Unexpected end-of-line in section header");
1072
- goto end_error;
1073
- }
1074
-
1075
- default:
1076
- break;
1077
- }
1078
-
1079
- git_buf_putc(&buf, (char)c);
1080
- c = line[++rpos];
1081
- } while (line + rpos < last_quote);
1082
-
1083
- end_parse:
1084
- if (git_buf_oom(&buf))
1085
- goto end_error;
1086
-
1087
- if (line[rpos] != '"' || line[rpos + 1] != ']') {
1088
- set_parse_error(reader, rpos, "Unexpected text after closing quotes");
1089
- git_buf_free(&buf);
1090
- return -1;
1091
- }
1092
-
1093
- *section_name = git_buf_detach(&buf);
1094
- return 0;
1095
-
1096
- end_error:
1097
- git_buf_free(&buf);
1098
-
1099
- return -1;
1100
- }
1101
-
1102
- static int parse_section_header(struct reader *reader, char **section_out)
1103
- {
1104
- char *name, *name_end;
1105
- int name_length, c, pos;
1106
- int result;
1107
- char *line;
1108
- size_t line_len;
1109
-
1110
- line = reader_readline(reader, true);
1111
- if (line == NULL)
1112
- return -1;
1113
-
1114
- /* find the end of the variable's name */
1115
- name_end = strrchr(line, ']');
1116
- if (name_end == NULL) {
1117
- git__free(line);
1118
- set_parse_error(reader, 0, "Missing ']' in section header");
1119
- return -1;
1120
- }
1121
-
1122
- GITERR_CHECK_ALLOC_ADD(&line_len, (size_t)(name_end - line), 1);
1123
- name = git__malloc(line_len);
1124
- GITERR_CHECK_ALLOC(name);
1125
-
1126
- name_length = 0;
1127
- pos = 0;
1128
-
1129
- /* Make sure we were given a section header */
1130
- c = line[pos++];
1131
- assert(c == '[');
1132
-
1133
- c = line[pos++];
1134
-
1135
- do {
1136
- if (git__isspace(c)){
1137
- name[name_length] = '\0';
1138
- result = parse_section_header_ext(reader, line, name, section_out);
1139
- git__free(line);
1140
- git__free(name);
1141
- return result;
1142
- }
1143
-
1144
- if (!config_keychar(c) && c != '.') {
1145
- set_parse_error(reader, pos, "Unexpected character in header");
1146
- goto fail_parse;
1147
- }
1148
-
1149
- name[name_length++] = (char)git__tolower(c);
1150
-
1151
- } while ((c = line[pos++]) != ']');
1152
-
1153
- if (line[pos - 1] != ']') {
1154
- set_parse_error(reader, pos, "Unexpected end of file");
1155
- goto fail_parse;
1156
- }
1157
-
1158
- git__free(line);
1159
-
1160
- name[name_length] = 0;
1161
- *section_out = name;
1162
-
1163
- return 0;
1164
-
1165
- fail_parse:
1166
- git__free(line);
1167
- git__free(name);
1168
- return -1;
1169
- }
1170
-
1171
- static int skip_bom(struct reader *reader)
1172
- {
1173
- git_bom_t bom;
1174
- int bom_offset = git_buf_text_detect_bom(&bom,
1175
- &reader->buffer, reader->read_ptr - reader->buffer.ptr);
1176
-
1177
- if (bom == GIT_BOM_UTF8)
1178
- reader->read_ptr += bom_offset;
1179
-
1180
- /* TODO: reference implementation is pretty stupid with BoM */
1181
-
1182
- return 0;
1183
- }
1184
-
1185
- /*
1186
- (* basic types *)
1187
- digit = "0".."9"
1188
- integer = digit { digit }
1189
- alphabet = "a".."z" + "A" .. "Z"
1190
-
1191
- section_char = alphabet | "." | "-"
1192
- extension_char = (* any character except newline *)
1193
- any_char = (* any character *)
1194
- variable_char = "alphabet" | "-"
1195
-
1196
-
1197
- (* actual grammar *)
1198
- config = { section }
1199
-
1200
- section = header { definition }
1201
-
1202
- header = "[" section [subsection | subsection_ext] "]"
1203
-
1204
- subsection = "." section
1205
- subsection_ext = "\"" extension "\""
1206
-
1207
- section = section_char { section_char }
1208
- extension = extension_char { extension_char }
1209
-
1210
- definition = variable_name ["=" variable_value] "\n"
1211
-
1212
- variable_name = variable_char { variable_char }
1213
- variable_value = string | boolean | integer
1214
-
1215
- string = quoted_string | plain_string
1216
- quoted_string = "\"" plain_string "\""
1217
- plain_string = { any_char }
1218
-
1219
- boolean = boolean_true | boolean_false
1220
- boolean_true = "yes" | "1" | "true" | "on"
1221
- boolean_false = "no" | "0" | "false" | "off"
1222
- */
1223
-
1224
- static int strip_comments(char *line, int in_quotes)
1225
- {
1226
- int quote_count = in_quotes, backslash_count = 0;
1227
- char *ptr;
1228
-
1229
- for (ptr = line; *ptr; ++ptr) {
1230
- if (ptr[0] == '"' && ptr > line && ptr[-1] != '\\')
1231
- quote_count++;
1232
-
1233
- if ((ptr[0] == ';' || ptr[0] == '#') &&
1234
- (quote_count % 2) == 0 &&
1235
- (backslash_count % 2) == 0) {
1236
- ptr[0] = '\0';
1237
- break;
1238
- }
1239
-
1240
- if (ptr[0] == '\\')
1241
- backslash_count++;
1242
- else
1243
- backslash_count = 0;
1244
- }
1245
-
1246
- /* skip any space at the end */
1247
- while (ptr > line && git__isspace(ptr[-1])) {
1248
- ptr--;
1249
- }
1250
- ptr[0] = '\0';
1251
-
1252
- return quote_count;
1253
- }
1254
-
1255
872
  static int included_path(git_buf *out, const char *dir, const char *path)
1256
873
  {
1257
874
  /* From the user's home */
@@ -1261,9 +878,6 @@ static int included_path(git_buf *out, const char *dir, const char *path)
1261
878
  return git_path_join_unrooted(out, path, dir, NULL);
1262
879
  }
1263
880
 
1264
- static const char *escapes = "ntb\"\\";
1265
- static const char *escaped = "\n\t\b\"\\";
1266
-
1267
881
  /* Escape the values to write them to the file */
1268
882
  static char *escape_value(const char *ptr)
1269
883
  {
@@ -1281,9 +895,9 @@ static char *escape_value(const char *ptr)
1281
895
  return NULL;
1282
896
 
1283
897
  while (*ptr != '\0') {
1284
- if ((esc = strchr(escaped, *ptr)) != NULL) {
898
+ if ((esc = strchr(git_config_escaped, *ptr)) != NULL) {
1285
899
  git_buf_putc(&buf, '\\');
1286
- git_buf_putc(&buf, escapes[esc - escaped]);
900
+ git_buf_putc(&buf, git_config_escapes[esc - git_config_escaped]);
1287
901
  } else {
1288
902
  git_buf_putc(&buf, *ptr);
1289
903
  }
@@ -1298,266 +912,151 @@ static char *escape_value(const char *ptr)
1298
912
  return git_buf_detach(&buf);
1299
913
  }
1300
914
 
1301
- /* '\"' -> '"' etc */
1302
- static int unescape_line(
1303
- char **out, bool *is_multi, const char *ptr, int quote_count)
1304
- {
1305
- char *str, *fixed, *esc;
1306
- size_t ptr_len = strlen(ptr), alloc_len;
1307
-
1308
- *is_multi = false;
1309
-
1310
- if (GIT_ADD_SIZET_OVERFLOW(&alloc_len, ptr_len, 1) ||
1311
- (str = git__malloc(alloc_len)) == NULL) {
1312
- return -1;
1313
- }
1314
-
1315
- fixed = str;
1316
-
1317
- while (*ptr != '\0') {
1318
- if (*ptr == '"') {
1319
- quote_count++;
1320
- } else if (*ptr != '\\') {
1321
- *fixed++ = *ptr;
1322
- } else {
1323
- /* backslash, check the next char */
1324
- ptr++;
1325
- /* if we're at the end, it's a multiline, so keep the backslash */
1326
- if (*ptr == '\0') {
1327
- *is_multi = true;
1328
- goto done;
1329
- }
1330
- if ((esc = strchr(escapes, *ptr)) != NULL) {
1331
- *fixed++ = escaped[esc - escapes];
1332
- } else {
1333
- git__free(str);
1334
- giterr_set(GITERR_CONFIG, "invalid escape at %s", ptr);
1335
- return -1;
1336
- }
1337
- }
1338
- ptr++;
1339
- }
1340
-
1341
- done:
1342
- *fixed = '\0';
1343
- *out = str;
1344
-
1345
- return 0;
1346
- }
915
+ struct parse_data {
916
+ const git_repository *repo;
917
+ const char *file_path;
918
+ git_strmap *values;
919
+ git_config_level_t level;
920
+ int depth;
921
+ };
1347
922
 
1348
- static int parse_multiline_variable(struct reader *reader, git_buf *value, int in_quotes)
923
+ static int parse_include(git_config_parser *reader,
924
+ struct parse_data *parse_data, const char *file)
1349
925
  {
1350
- int quote_count;
1351
- bool multiline = true;
1352
-
1353
- while (multiline) {
1354
- char *line = NULL, *proc_line = NULL;
1355
- int error;
1356
-
1357
- /* Check that the next line exists */
1358
- line = reader_readline(reader, false);
1359
- GITERR_CHECK_ALLOC(line);
1360
-
1361
- /*
1362
- * We've reached the end of the file, there is no continuation.
1363
- * (this is not an error).
1364
- */
1365
- if (line[0] == '\0') {
1366
- error = 0;
1367
- goto out;
1368
- }
926
+ struct config_file *include;
927
+ git_buf path = GIT_BUF_INIT;
928
+ char *dir;
929
+ int result;
1369
930
 
1370
- /* If it was just a comment, pretend it didn't exist */
1371
- quote_count = strip_comments(line, !!in_quotes);
1372
- if (line[0] == '\0')
1373
- goto next;
931
+ if ((result = git_path_dirname_r(&path, reader->file->path)) < 0)
932
+ return result;
1374
933
 
1375
- if ((error = unescape_line(&proc_line, &multiline,
1376
- line, in_quotes)) < 0)
1377
- goto out;
934
+ dir = git_buf_detach(&path);
935
+ result = included_path(&path, dir, file);
936
+ git__free(dir);
1378
937
 
1379
- /* Add this line to the multiline var */
1380
- if ((error = git_buf_puts(value, proc_line)) < 0)
1381
- goto out;
938
+ if (result < 0)
939
+ return result;
1382
940
 
1383
- next:
1384
- git__free(line);
1385
- git__free(proc_line);
1386
- in_quotes = quote_count;
1387
- continue;
941
+ include = git_array_alloc(reader->file->includes);
942
+ memset(include, 0, sizeof(*include));
943
+ git_array_init(include->includes);
944
+ include->path = git_buf_detach(&path);
1388
945
 
1389
- out:
1390
- git__free(line);
1391
- git__free(proc_line);
1392
- return error;
1393
- }
946
+ result = config_read(parse_data->values, parse_data->repo,
947
+ include, parse_data->level, parse_data->depth+1);
1394
948
 
1395
- return 0;
1396
- }
949
+ if (result == GIT_ENOTFOUND) {
950
+ giterr_clear();
951
+ result = 0;
952
+ }
1397
953
 
1398
- GIT_INLINE(bool) is_namechar(char c)
1399
- {
1400
- return isalnum(c) || c == '-';
954
+ return result;
1401
955
  }
1402
956
 
1403
- static int parse_name(
1404
- char **name, const char **value, struct reader *reader, const char *line)
957
+ static int do_match_gitdir(
958
+ int *matches,
959
+ const git_repository *repo,
960
+ const char *cfg_file,
961
+ const char *value,
962
+ bool case_insensitive)
1405
963
  {
1406
- const char *name_end = line, *value_start;
964
+ git_buf path = GIT_BUF_INIT;
965
+ int error, fnmatch_flags;
1407
966
 
1408
- *name = NULL;
1409
- *value = NULL;
1410
-
1411
- while (*name_end && is_namechar(*name_end))
1412
- name_end++;
967
+ if (value[0] == '.' && git_path_is_dirsep(value[1])) {
968
+ git_path_dirname_r(&path, cfg_file);
969
+ git_buf_joinpath(&path, path.ptr, value + 2);
970
+ } else if (value[0] == '~' && git_path_is_dirsep(value[1]))
971
+ git_sysdir_expand_global_file(&path, value + 1);
972
+ else if (!git_path_is_absolute(value))
973
+ git_buf_joinpath(&path, "**", value);
974
+ else
975
+ git_buf_sets(&path, value);
1413
976
 
1414
- if (line == name_end) {
1415
- set_parse_error(reader, 0, "Invalid configuration key");
1416
- return -1;
977
+ if (git_buf_oom(&path)) {
978
+ error = -1;
979
+ goto out;
1417
980
  }
1418
981
 
1419
- value_start = name_end;
982
+ if (git_path_is_dirsep(value[strlen(value) - 1]))
983
+ git_buf_puts(&path, "**");
1420
984
 
1421
- while (*value_start && git__isspace(*value_start))
1422
- value_start++;
985
+ fnmatch_flags = FNM_PATHNAME|FNM_LEADING_DIR;
986
+ if (case_insensitive)
987
+ fnmatch_flags |= FNM_IGNORECASE;
1423
988
 
1424
- if (*value_start == '=') {
1425
- *value = value_start + 1;
1426
- } else if (*value_start) {
1427
- set_parse_error(reader, 0, "Invalid configuration key");
1428
- return -1;
1429
- }
989
+ if ((error = p_fnmatch(path.ptr, git_repository_path(repo), fnmatch_flags)) < 0)
990
+ goto out;
1430
991
 
1431
- if ((*name = git__strndup(line, name_end - line)) == NULL)
1432
- return -1;
992
+ *matches = (error == 0);
1433
993
 
1434
- return 0;
994
+ out:
995
+ git_buf_free(&path);
996
+ return error;
1435
997
  }
1436
998
 
1437
- static int parse_variable(struct reader *reader, char **var_name, char **var_value)
999
+ static int conditional_match_gitdir(
1000
+ int *matches,
1001
+ const git_repository *repo,
1002
+ const char *cfg_file,
1003
+ const char *value)
1438
1004
  {
1439
- const char *value_start = NULL;
1440
- char *line;
1441
- int quote_count;
1442
- bool multiline;
1443
-
1444
- line = reader_readline(reader, true);
1445
- if (line == NULL)
1446
- return -1;
1447
-
1448
- quote_count = strip_comments(line, 0);
1449
-
1450
- /* If there is no value, boolean true is assumed */
1451
- *var_value = NULL;
1452
-
1453
- if (parse_name(var_name, &value_start, reader, line) < 0)
1454
- goto on_error;
1455
-
1456
- /*
1457
- * Now, let's try to parse the value
1458
- */
1459
- if (value_start != NULL) {
1460
- while (git__isspace(value_start[0]))
1461
- value_start++;
1462
-
1463
- if (unescape_line(var_value, &multiline, value_start, 0) < 0)
1464
- goto on_error;
1465
-
1466
- if (multiline) {
1467
- git_buf multi_value = GIT_BUF_INIT;
1468
- git_buf_attach(&multi_value, *var_value, 0);
1469
-
1470
- if (parse_multiline_variable(reader, &multi_value, quote_count) < 0 ||
1471
- git_buf_oom(&multi_value)) {
1472
- git_buf_free(&multi_value);
1473
- goto on_error;
1474
- }
1475
-
1476
- *var_value = git_buf_detach(&multi_value);
1477
- }
1478
- }
1479
-
1480
- git__free(line);
1481
- return 0;
1482
-
1483
- on_error:
1484
- git__free(*var_name);
1485
- git__free(line);
1486
- return -1;
1005
+ return do_match_gitdir(matches, repo, cfg_file, value, false);
1487
1006
  }
1488
1007
 
1489
- static int config_parse(
1490
- struct reader *reader,
1491
- int (*on_section)(struct reader **reader, const char *current_section, const char *line, size_t line_len, void *data),
1492
- int (*on_variable)(struct reader **reader, const char *current_section, char *var_name, char *var_value, const char *line, size_t line_len, void *data),
1493
- int (*on_comment)(struct reader **reader, const char *line, size_t line_len, void *data),
1494
- int (*on_eof)(struct reader **reader, const char *current_section, void *data),
1495
- void *data)
1008
+ static int conditional_match_gitdir_i(
1009
+ int *matches,
1010
+ const git_repository *repo,
1011
+ const char *cfg_file,
1012
+ const char *value)
1496
1013
  {
1497
- char *current_section = NULL, *var_name, *var_value, *line_start;
1498
- char c;
1499
- size_t line_len;
1500
- int result = 0;
1014
+ return do_match_gitdir(matches, repo, cfg_file, value, true);
1015
+ }
1501
1016
 
1502
- skip_bom(reader);
1017
+ static const struct {
1018
+ const char *prefix;
1019
+ int (*matches)(int *matches, const git_repository *repo, const char *cfg, const char *value);
1020
+ } conditions[] = {
1021
+ { "gitdir:", conditional_match_gitdir },
1022
+ { "gitdir/i:", conditional_match_gitdir_i }
1023
+ };
1503
1024
 
1504
- while (result == 0 && !reader->eof) {
1505
- line_start = reader->read_ptr;
1025
+ static int parse_conditional_include(git_config_parser *reader,
1026
+ struct parse_data *parse_data, const char *section, const char *file)
1027
+ {
1028
+ char *condition;
1029
+ size_t i;
1030
+ int error = 0, matches;
1506
1031
 
1507
- c = reader_peek(reader, SKIP_WHITESPACE);
1032
+ if (!parse_data->repo)
1033
+ return 0;
1508
1034
 
1509
- switch (c) {
1510
- case '\0': /* EOF when peeking, set EOF in the reader to exit the loop */
1511
- reader->eof = 1;
1512
- break;
1035
+ condition = git__substrdup(section + strlen("includeIf."),
1036
+ strlen(section) - strlen("includeIf.") - strlen(".path"));
1513
1037
 
1514
- case '[': /* section header, new section begins */
1515
- git__free(current_section);
1516
- current_section = NULL;
1038
+ for (i = 0; i < ARRAY_SIZE(conditions); i++) {
1039
+ if (git__prefixcmp(condition, conditions[i].prefix))
1040
+ continue;
1517
1041
 
1518
- if ((result = parse_section_header(reader, &current_section)) == 0 && on_section) {
1519
- line_len = reader->read_ptr - line_start;
1520
- result = on_section(&reader, current_section, line_start, line_len, data);
1521
- }
1042
+ if ((error = conditions[i].matches(&matches,
1043
+ parse_data->repo,
1044
+ parse_data->file_path,
1045
+ condition + strlen(conditions[i].prefix))) < 0)
1522
1046
  break;
1523
1047
 
1524
- case '\n': /* comment or whitespace-only */
1525
- case ';':
1526
- case '#':
1527
- reader_consume_line(reader);
1048
+ if (matches)
1049
+ error = parse_include(reader, parse_data, file);
1528
1050
 
1529
- if (on_comment) {
1530
- line_len = reader->read_ptr - line_start;
1531
- result = on_comment(&reader, line_start, line_len, data);
1532
- }
1533
- break;
1534
-
1535
- default: /* assume variable declaration */
1536
- if ((result = parse_variable(reader, &var_name, &var_value)) == 0 && on_variable) {
1537
- line_len = reader->read_ptr - line_start;
1538
- result = on_variable(&reader, current_section, var_name, var_value, line_start, line_len, data);
1539
- }
1540
- break;
1541
- }
1051
+ break;
1542
1052
  }
1543
1053
 
1544
- if (on_eof)
1545
- result = on_eof(&reader, current_section, data);
1546
-
1547
- git__free(current_section);
1548
- return result;
1054
+ git__free(condition);
1055
+ return error;
1549
1056
  }
1550
1057
 
1551
- struct parse_data {
1552
- git_strmap *values;
1553
- diskfile_backend *cfg_file;
1554
- uint32_t reader_idx;
1555
- git_config_level_t level;
1556
- int depth;
1557
- };
1558
-
1559
1058
  static int read_on_variable(
1560
- struct reader **reader,
1059
+ git_config_parser *reader,
1561
1060
  const char *current_section,
1562
1061
  char *var_name,
1563
1062
  char *var_value,
@@ -1598,74 +1097,61 @@ static int read_on_variable(
1598
1097
  result = 0;
1599
1098
 
1600
1099
  /* Add or append the new config option */
1601
- if (!git__strcmp(var->entry->name, "include.path") && var->entry->value) {
1602
- struct reader *r;
1603
- git_buf path = GIT_BUF_INIT;
1604
- char *dir;
1605
- uint32_t index;
1606
-
1607
- r = git_array_alloc(parse_data->cfg_file->readers);
1608
- /* The reader may have been reallocated */
1609
- *reader = git_array_get(parse_data->cfg_file->readers, parse_data->reader_idx);
1610
- memset(r, 0, sizeof(struct reader));
1611
-
1612
- if ((result = git_path_dirname_r(&path, (*reader)->file_path)) < 0)
1613
- return result;
1100
+ if (!git__strcmp(var->entry->name, "include.path"))
1101
+ result = parse_include(reader, parse_data, var->entry->value);
1102
+ else if (!git__prefixcmp(var->entry->name, "includeif.") &&
1103
+ !git__suffixcmp(var->entry->name, ".path"))
1104
+ result = parse_conditional_include(reader, parse_data,
1105
+ var->entry->name, var->entry->value);
1614
1106
 
1615
- /* We need to know our index in the array, as the next config_parse call may realloc */
1616
- index = git_array_size(parse_data->cfg_file->readers) - 1;
1617
- dir = git_buf_detach(&path);
1618
- result = included_path(&path, dir, var->entry->value);
1619
- git__free(dir);
1620
-
1621
- if (result < 0)
1622
- return result;
1623
-
1624
- r->file_path = git_buf_detach(&path);
1625
- git_buf_init(&r->buffer, 0);
1626
-
1627
- result = git_futils_readbuffer_updated(
1628
- &r->buffer, r->file_path, &r->checksum, NULL);
1629
-
1630
- if (result == 0) {
1631
- result = config_read(parse_data->values, parse_data->cfg_file, r, parse_data->level, parse_data->depth+1);
1632
- r = git_array_get(parse_data->cfg_file->readers, index);
1633
- *reader = git_array_get(parse_data->cfg_file->readers, parse_data->reader_idx);
1634
- } else if (result == GIT_ENOTFOUND) {
1635
- giterr_clear();
1636
- result = 0;
1637
- }
1638
-
1639
- git_buf_free(&r->buffer);
1640
- }
1641
1107
 
1642
1108
  return result;
1643
1109
  }
1644
1110
 
1645
- static int config_read(git_strmap *values, diskfile_backend *cfg_file, struct reader *reader, git_config_level_t level, int depth)
1111
+ static int config_read(
1112
+ git_strmap *values,
1113
+ const git_repository *repo,
1114
+ git_config_file *file,
1115
+ git_config_level_t level,
1116
+ int depth)
1646
1117
  {
1647
1118
  struct parse_data parse_data;
1119
+ git_config_parser reader;
1120
+ git_buf contents = GIT_BUF_INIT;
1121
+ int error;
1648
1122
 
1649
1123
  if (depth >= MAX_INCLUDE_DEPTH) {
1650
1124
  giterr_set(GITERR_CONFIG, "maximum config include depth reached");
1651
1125
  return -1;
1652
1126
  }
1653
1127
 
1128
+ if ((error = git_futils_readbuffer(&contents, file->path)) < 0)
1129
+ goto out;
1130
+
1131
+ git_parse_ctx_init(&reader.ctx, contents.ptr, contents.size);
1132
+
1133
+ if ((error = git_hash_buf(&file->checksum, contents.ptr, contents.size)) < 0)
1134
+ goto out;
1135
+
1654
1136
  /* Initialize the reading position */
1655
- reader->read_ptr = reader->buffer.ptr;
1656
- reader->eof = 0;
1137
+ reader.file = file;
1138
+ git_parse_ctx_init(&reader.ctx, contents.ptr, contents.size);
1657
1139
 
1658
1140
  /* If the file is empty, there's nothing for us to do */
1659
- if (*reader->read_ptr == '\0')
1660
- return 0;
1141
+ if (!reader.ctx.content || *reader.ctx.content == '\0')
1142
+ goto out;
1661
1143
 
1144
+ parse_data.repo = repo;
1145
+ parse_data.file_path = file->path;
1662
1146
  parse_data.values = values;
1663
- parse_data.cfg_file = cfg_file;
1664
- parse_data.reader_idx = git_array_size(cfg_file->readers) - 1;
1665
1147
  parse_data.level = level;
1666
1148
  parse_data.depth = depth;
1667
1149
 
1668
- return config_parse(reader, NULL, read_on_variable, NULL, NULL, &parse_data);
1150
+ error = git_config_parse(&reader, NULL, read_on_variable, NULL, NULL, &parse_data);
1151
+
1152
+ out:
1153
+ git_buf_free(&contents);
1154
+ return error;
1669
1155
  }
1670
1156
 
1671
1157
  static int write_section(git_buf *fbuf, const char *key)
@@ -1721,7 +1207,9 @@ struct write_data {
1721
1207
  git_buf buffered_comment;
1722
1208
  unsigned int in_section : 1,
1723
1209
  preg_replaced : 1;
1210
+ const char *orig_section;
1724
1211
  const char *section;
1212
+ const char *orig_name;
1725
1213
  const char *name;
1726
1214
  const regex_t *preg;
1727
1215
  const char *value;
@@ -1749,7 +1237,7 @@ static int write_value(struct write_data *write_data)
1749
1237
 
1750
1238
  q = quotes_for_value(write_data->value);
1751
1239
  result = git_buf_printf(write_data->buf,
1752
- "\t%s = %s%s%s\n", write_data->name, q, write_data->value, q);
1240
+ "\t%s = %s%s%s\n", write_data->orig_name, q, write_data->value, q);
1753
1241
 
1754
1242
  /* If we are updating a single name/value, we're done. Setting `value`
1755
1243
  * to `NULL` will prevent us from trying to write it again later (in
@@ -1762,7 +1250,7 @@ static int write_value(struct write_data *write_data)
1762
1250
  }
1763
1251
 
1764
1252
  static int write_on_section(
1765
- struct reader **reader,
1253
+ git_config_parser *reader,
1766
1254
  const char *current_section,
1767
1255
  const char *line,
1768
1256
  size_t line_len,
@@ -1798,7 +1286,7 @@ static int write_on_section(
1798
1286
  }
1799
1287
 
1800
1288
  static int write_on_variable(
1801
- struct reader **reader,
1289
+ git_config_parser *reader,
1802
1290
  const char *current_section,
1803
1291
  char *var_name,
1804
1292
  char *var_value,
@@ -1848,7 +1336,7 @@ static int write_on_variable(
1848
1336
  return write_value(write_data);
1849
1337
  }
1850
1338
 
1851
- static int write_on_comment(struct reader **reader, const char *line, size_t line_len, void *data)
1339
+ static int write_on_comment(git_config_parser *reader, const char *line, size_t line_len, void *data)
1852
1340
  {
1853
1341
  struct write_data *write_data;
1854
1342
 
@@ -1859,7 +1347,7 @@ static int write_on_comment(struct reader **reader, const char *line, size_t lin
1859
1347
  }
1860
1348
 
1861
1349
  static int write_on_eof(
1862
- struct reader **reader, const char *current_section, void *data)
1350
+ git_config_parser *reader, const char *current_section, void *data)
1863
1351
  {
1864
1352
  struct write_data *write_data = (struct write_data *)data;
1865
1353
  int result = 0;
@@ -1880,7 +1368,7 @@ static int write_on_eof(
1880
1368
  if ((!write_data->preg || !write_data->preg_replaced) && write_data->value) {
1881
1369
  /* write the section header unless we're already in it */
1882
1370
  if (!current_section || strcmp(current_section, write_data->section))
1883
- result = write_section(write_data->buf, write_data->section);
1371
+ result = write_section(write_data->buf, write_data->orig_section);
1884
1372
 
1885
1373
  if (!result)
1886
1374
  result = write_value(write_data);
@@ -1892,37 +1380,35 @@ static int write_on_eof(
1892
1380
  /*
1893
1381
  * This is pretty much the parsing, except we write out anything we don't have
1894
1382
  */
1895
- static int config_write(diskfile_backend *cfg, const char *key, const regex_t *preg, const char* value)
1383
+ static int config_write(diskfile_backend *cfg, const char *orig_key, const char *key, const regex_t *preg, const char* value)
1896
1384
  {
1897
1385
  int result;
1898
- char *section, *name, *ldot;
1386
+ char *orig_section, *section, *orig_name, *name, *ldot;
1899
1387
  git_filebuf file = GIT_FILEBUF_INIT;
1900
- git_buf buf = GIT_BUF_INIT;
1901
- struct reader *reader = git_array_get(cfg->readers, 0);
1388
+ git_buf buf = GIT_BUF_INIT, contents = GIT_BUF_INIT;
1389
+ git_config_parser reader;
1902
1390
  struct write_data write_data;
1903
1391
 
1392
+ memset(&reader, 0, sizeof(reader));
1393
+ reader.file = &cfg->file;
1394
+
1904
1395
  if (cfg->locked) {
1905
- result = git_buf_puts(&reader->buffer, git_buf_cstr(&cfg->locked_content));
1396
+ result = git_buf_puts(&contents, git_buf_cstr(&cfg->locked_content));
1906
1397
  } else {
1907
1398
  /* Lock the file */
1908
1399
  if ((result = git_filebuf_open(
1909
- &file, cfg->file_path, GIT_FILEBUF_HASH_CONTENTS, GIT_CONFIG_FILE_MODE)) < 0) {
1910
- git_buf_free(&reader->buffer);
1400
+ &file, cfg->file.path, GIT_FILEBUF_HASH_CONTENTS, GIT_CONFIG_FILE_MODE)) < 0) {
1401
+ git_buf_free(&contents);
1911
1402
  return result;
1912
1403
  }
1913
1404
 
1914
1405
  /* We need to read in our own config file */
1915
- result = git_futils_readbuffer(&reader->buffer, cfg->file_path);
1406
+ result = git_futils_readbuffer(&contents, cfg->file.path);
1916
1407
  }
1917
1408
 
1918
1409
  /* Initialise the reading position */
1919
- if (result == GIT_ENOTFOUND) {
1920
- reader->read_ptr = NULL;
1921
- reader->eof = 1;
1922
- git_buf_clear(&reader->buffer);
1923
- } else if (result == 0) {
1924
- reader->read_ptr = reader->buffer.ptr;
1925
- reader->eof = 0;
1410
+ if (result == 0 || result == GIT_ENOTFOUND) {
1411
+ git_parse_ctx_init(&reader.ctx, contents.ptr, contents.size);
1926
1412
  } else {
1927
1413
  git_filebuf_cleanup(&file);
1928
1414
  return -1; /* OS error when reading the file */
@@ -1931,18 +1417,32 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
1931
1417
  ldot = strrchr(key, '.');
1932
1418
  name = ldot + 1;
1933
1419
  section = git__strndup(key, ldot - key);
1420
+ GITERR_CHECK_ALLOC(section);
1421
+
1422
+ ldot = strrchr(orig_key, '.');
1423
+ orig_name = ldot + 1;
1424
+ orig_section = git__strndup(orig_key, ldot - orig_key);
1425
+ GITERR_CHECK_ALLOC(orig_section);
1934
1426
 
1935
1427
  write_data.buf = &buf;
1936
1428
  git_buf_init(&write_data.buffered_comment, 0);
1429
+ write_data.orig_section = orig_section;
1937
1430
  write_data.section = section;
1938
1431
  write_data.in_section = 0;
1939
1432
  write_data.preg_replaced = 0;
1433
+ write_data.orig_name = orig_name;
1940
1434
  write_data.name = name;
1941
1435
  write_data.preg = preg;
1942
1436
  write_data.value = value;
1943
1437
 
1944
- result = config_parse(reader, write_on_section, write_on_variable, write_on_comment, write_on_eof, &write_data);
1438
+ result = git_config_parse(&reader,
1439
+ write_on_section,
1440
+ write_on_variable,
1441
+ write_on_comment,
1442
+ write_on_eof,
1443
+ &write_data);
1945
1444
  git__free(section);
1445
+ git__free(orig_section);
1946
1446
  git_buf_free(&write_data.buffered_comment);
1947
1447
 
1948
1448
  if (result < 0) {
@@ -1962,6 +1462,7 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
1962
1462
 
1963
1463
  done:
1964
1464
  git_buf_free(&buf);
1965
- git_buf_free(&reader->buffer);
1465
+ git_buf_free(&contents);
1466
+ git_parse_ctx_clear(&reader.ctx);
1966
1467
  return result;
1967
1468
  }