rugged 0.26.7 → 0.27.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }