2525#include "php_git2.h"
2626#include <spl/spl_array.h>
2727#include <zend_interfaces.h>
28-
28+
2929PHPAPI zend_class_entry * git2_walker_class_entry ;
3030
31+ static const double resize_factor = 1.75 ;
32+ static const unsigned int minimum_size = 8 ;
33+
34+ typedef struct {
35+ git_oid oid ;
36+ unsigned int interested ;
37+ } php_git2_revwalk_element ;
38+
39+ int php_git2_vector_init (php_git2_vector * v , size_t initial_size )
40+ {
41+ assert (v );
42+ memset (v , 0x0 , sizeof (php_git2_vector ));
43+
44+ if (initial_size == 0 ) {
45+ initial_size = minimum_size ;
46+ }
47+
48+ v -> _alloc_size = initial_size ;
49+ v -> length = 0 ;
50+
51+ v -> contents = emalloc (v -> _alloc_size * sizeof (void * ));
52+ }
53+
54+ static int php_git2_resize_vector (php_git2_vector * v )
55+ {
56+ v -> _alloc_size = ((unsigned int )(v -> _alloc_size * resize_factor )) + 1 ;
57+ if (v -> _alloc_size < minimum_size )
58+ v -> _alloc_size = minimum_size ;
59+
60+ v -> contents = erealloc (v -> contents , v -> _alloc_size * sizeof (void * ));
61+
62+ return 0 ;
63+ }
64+
65+ int php_git2_vector_insert (php_git2_vector * v , void * element )
66+ {
67+ assert (v );
68+
69+ if (v -> length >= v -> _alloc_size && php_git2_resize_vector (v ) < 0 ) {
70+ return -1 ;
71+ }
72+
73+ v -> contents [v -> length ++ ] = element ;
74+ return 0 ;
75+ }
76+
77+ void php_git2_vector_clear (php_git2_vector * v )
78+ {
79+ assert (v );
80+ v -> length = 0 ;
81+ }
82+
83+ void php_git2_vector_free (php_git2_vector * v )
84+ {
85+ assert (v );
86+
87+ efree (v -> contents );
88+ v -> contents = NULL ;
89+
90+ v -> length = 0 ;
91+ v -> _alloc_size = 0 ;
92+ }
93+
94+
3195static void php_git2_walker_free_storage (php_git2_walker * object TSRMLS_DC )
3296{
97+ int i = 0 ;
3398 if (object -> walker != NULL ) {
3499 git_revwalk_free (object -> walker );
35100 object -> walker = NULL ;
@@ -39,6 +104,11 @@ static void php_git2_walker_free_storage(php_git2_walker *object TSRMLS_DC)
39104 object -> current = NULL ;
40105 }
41106
107+ for (i = 0 ; i < object -> vector .length ; i ++ ) {
108+ efree (object -> vector .contents [i ]);
109+ }
110+ php_git2_vector_free (& object -> vector );
111+
42112 /* the repository will be free'd by Git2\Repository */
43113 object -> repository = NULL ;
44114
@@ -51,8 +121,11 @@ zend_object_value php_git2_walker_new(zend_class_entry *ce TSRMLS_DC)
51121 zend_object_value retval ;
52122
53123 PHP_GIT2_STD_CREATE_OBJECT (php_git2_walker );
124+ object -> dirty = 0 ;
54125
55126 object -> current = emalloc (sizeof (git_oid ));
127+ php_git2_vector_init (& object -> vector , 8 );
128+
56129 return retval ;
57130}
58131
@@ -93,8 +166,9 @@ PHP_METHOD(git2_walker, __construct)
93166 error = git_revwalk_new (& m_walker -> walker , m_repository -> repository );
94167
95168 if (error != GIT_OK ) {
96- /* @todo error handling */
169+ zend_throw_exception_ex ( spl_ce_RuntimeException , 0 TSRMLS_CC , "can't create a Git2\\Walker instance." );
97170 }
171+
98172 m_walker -> repository = m_repository -> repository ;
99173}
100174/* }}} */
@@ -124,8 +198,8 @@ PHP_METHOD(git2_walker, push)
124198{
125199 php_git2_walker * m_walker ;
126200 char * sha ;
127- int sha_len = 0 ;
128- git_oid oid ;
201+ int sha_len = 0 , error = 0 ;
202+ php_git2_revwalk_element * elm ;
129203
130204 /* @todo: also supports Git2\Commit object */
131205 if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC ,
@@ -134,11 +208,17 @@ PHP_METHOD(git2_walker, push)
134208 }
135209
136210 m_walker = PHP_GIT2_GET_OBJECT (php_git2_walker , getThis ());
211+ elm = emalloc (sizeof (php_git2_revwalk_element ));
212+ elm -> interested = 1 ;
137213
138- git_oid_fromstrn (& oid , sha , sha_len );
139- git_revwalk_reset (m_walker -> walker );
140- git_revwalk_push (m_walker -> walker , & oid );
141- memcpy (m_walker -> current , & oid , sizeof (git_oid ));
214+ git_oid_fromstrn (& elm -> oid , sha , sha_len );
215+ error = git_revwalk_push (m_walker -> walker , & elm -> oid );
216+
217+ if (error != GIT_OK ) {
218+ zend_throw_exception_ex (spl_ce_RuntimeException , 0 TSRMLS_CC , "Git2\\Walker::push failed." );
219+ }
220+
221+ php_git2_vector_insert (& m_walker -> vector , elm );
142222}
143223/* }}} */
144224
@@ -149,8 +229,9 @@ PHP_METHOD(git2_walker, hide)
149229{
150230 php_git2_walker * m_walker ;
151231 char * sha ;
152- int sha_len = 0 ;
232+ int sha_len = 0 , error = 0 ;
153233 git_oid oid ;
234+ php_git2_revwalk_element * elm ;
154235
155236 /* @todo: also supports Git2\Commit object */
156237 if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC ,
@@ -159,8 +240,16 @@ PHP_METHOD(git2_walker, hide)
159240 }
160241
161242 m_walker = PHP_GIT2_GET_OBJECT (php_git2_walker , getThis ());
162- git_oid_fromstrn (& oid , sha , sha_len );
163- git_revwalk_hide (m_walker -> walker , & oid );
243+ elm = emalloc (sizeof (php_git2_revwalk_element ));
244+ elm -> interested = 0 ;
245+
246+ git_oid_fromstrn (& elm -> oid , sha , sha_len );
247+ error = git_revwalk_hide (m_walker -> walker , & elm -> oid );
248+
249+ if (error != GIT_OK ) {
250+ zend_throw_exception_ex (spl_ce_RuntimeException , 0 TSRMLS_CC , "Git2\\Walker::push failed." );
251+ }
252+ php_git2_vector_insert (& m_walker -> vector , elm );
164253}
165254/* }}} */
166255
@@ -171,9 +260,18 @@ PHP_METHOD(git2_walker, hide)
171260PHP_METHOD (git2_walker , reset )
172261{
173262 php_git2_walker * m_walker ;
263+ int i = 0 ;
174264
175- m_walker = PHP_GIT2_GET_OBJECT (php_git2_walker , getThis ());
265+ m_walker = PHP_GIT2_GET_OBJECT (php_git2_walker , getThis ());
176266 git_revwalk_reset (m_walker -> walker );
267+ m_walker -> dirty = 0 ;
268+
269+ for (i = 0 ; i < m_walker -> vector .length ; i ++ ) {
270+ php_git2_revwalk_element * elm = m_walker -> vector .contents [i ];
271+ efree (elm );
272+ }
273+
274+ php_git2_vector_clear (& m_walker -> vector );
177275}
178276/* }}} */
179277
@@ -191,9 +289,10 @@ PHP_METHOD(git2_walker, current)
191289 int error = 0 ;
192290
193291 m_walker = PHP_GIT2_GET_OBJECT (php_git2_walker , getThis ());
194- error = git_object_lookup (& object , m_walker -> repository , m_walker -> current , GIT_OBJ_COMMIT );
292+
293+ error = git_object_lookup (& object , m_walker -> repository , m_walker -> current , GIT_OBJ_COMMIT );
195294 result = php_git2_object_new (m_walker -> repository , object TSRMLS_CC );
196- RETVAL_ZVAL (result ,0 , 1 );
295+ RETVAL_ZVAL (result , 0 , 1 );
197296}
198297
199298/*
@@ -203,22 +302,26 @@ PHP_METHOD(git2_walker, key)
203302{
204303 char out [GIT_OID_HEXSZ ] = {0 };
205304 php_git2_walker * m_walker ;
305+ int error = 0 ;
206306
207- m_walker = PHP_GIT2_GET_OBJECT (php_git2_walker , getThis ());
307+ m_walker = PHP_GIT2_GET_OBJECT (php_git2_walker , getThis ());
208308 git_oid_fmt (out , m_walker -> current );
209- RETURN_STRINGL (out ,GIT_OID_HEXSZ ,1 );
309+
310+ RETURN_STRINGL (out , GIT_OID_HEXSZ , 1 );
210311}
211312
212313/*
213- {{{ proto: Git2\Walker::valid ()
314+ {{{ proto: Git2\Walker::next ()
214315*/
215316PHP_METHOD (git2_walker , next )
216317{
217318 php_git2_walker * m_walker ;
218319 int error = 0 ;
219320
220- m_walker = PHP_GIT2_GET_OBJECT (php_git2_walker , getThis ());
321+ m_walker = PHP_GIT2_GET_OBJECT (php_git2_walker , getThis ());
221322 error = git_revwalk_next (m_walker -> current , m_walker -> walker );
323+ m_walker -> dirty = 1 ;
324+
222325 if (error != GIT_OK ) {
223326 efree (m_walker -> current );
224327 m_walker -> current = NULL ;
@@ -231,16 +334,42 @@ PHP_METHOD(git2_walker, next)
231334PHP_METHOD (git2_walker , rewind )
232335{
233336 php_git2_walker * m_walker ;
234-
235- m_walker = PHP_GIT2_GET_OBJECT (php_git2_walker , getThis ());
236- git_revwalk_reset (m_walker -> walker );
237- if (m_walker -> current == NULL ) {
238- zend_throw_exception_ex (spl_ce_RuntimeException , 0 TSRMLS_CC ,
239- "does not specify interested hash before calling Git2\\Walker::rewind." );
240- RETURN_FALSE ;
337+ int i = 0 , error = 0 ;
338+ m_walker = PHP_GIT2_GET_OBJECT (php_git2_walker , getThis ());
339+
340+ if (m_walker -> dirty ) {
341+ git_revwalk_reset (m_walker -> walker );
342+
343+ for (i = 0 ; i < m_walker -> vector .length ; i ++ ) {
344+ php_git2_revwalk_element * elm = m_walker -> vector .contents [i ];
345+
346+ if (elm -> interested ) {
347+ error = git_revwalk_push (m_walker -> walker , & elm -> oid );
348+ } else {
349+ error = git_revwalk_hide (m_walker -> walker , & elm -> oid );
350+ }
351+
352+ if (error != GIT_OK ) {
353+ zend_throw_exception_ex (spl_ce_RuntimeException , 0 TSRMLS_CC , "Git2\\Walker::rewind failed. probably you pushed or hided invalied oid." );
354+ }
355+ }
356+
357+ if (m_walker -> current == NULL ) {
358+ m_walker -> current = emalloc (sizeof (git_oid ));
359+ }
360+
361+ assert (m_walker -> current );
362+ error = git_revwalk_next (m_walker -> current , m_walker -> walker );
363+ m_walker -> dirty = 1 ;
364+ } else {
365+ error = git_revwalk_next (m_walker -> current , m_walker -> walker );
366+ m_walker -> dirty = 1 ;
367+
368+ if (error != GIT_OK ) {
369+ zend_throw_exception_ex (spl_ce_RuntimeException , 0 TSRMLS_CC , "Git2\\Walker::rewind failed. probably you pushed or hided invalied oid." );
370+ }
241371 }
242- git_revwalk_push (m_walker -> walker , m_walker -> current );
243- git_revwalk_next (m_walker -> current , m_walker -> walker );
372+
244373}
245374
246375/*
@@ -249,8 +378,8 @@ PHP_METHOD(git2_walker, rewind)
249378PHP_METHOD (git2_walker , valid )
250379{
251380 php_git2_walker * m_walker ;
252-
253381 m_walker = PHP_GIT2_GET_OBJECT (php_git2_walker , getThis ());
382+
254383 if (m_walker -> current != NULL ) {
255384 RETURN_TRUE ;
256385 } else {
0 commit comments