2020#include "read-cache-ll.h"
2121#include "repository.h"
2222#include "setup.h"
23+ #include "strvec.h"
2324#include "submodule.h"
2425#include "entry.h"
2526
@@ -38,42 +39,32 @@ enum update_mode {
3839#define DUP_BASENAME 1
3940#define KEEP_TRAILING_SLASH 2
4041
41- static const char * * internal_prefix_pathspec (const char * prefix ,
42- const char * * pathspec ,
43- int count , unsigned flags )
42+ static void internal_prefix_pathspec (struct strvec * out ,
43+ const char * prefix ,
44+ const char * * pathspec ,
45+ int count , unsigned flags )
4446{
45- int i ;
46- const char * * result ;
4747 int prefixlen = prefix ? strlen (prefix ) : 0 ;
48- ALLOC_ARRAY (result , count + 1 );
4948
5049 /* Create an intermediate copy of the pathspec based on the flags */
51- for (i = 0 ; i < count ; i ++ ) {
52- int length = strlen (pathspec [i ]);
53- int to_copy = length ;
54- char * it ;
50+ for (int i = 0 ; i < count ; i ++ ) {
51+ size_t length = strlen (pathspec [i ]);
52+ size_t to_copy = length ;
53+ const char * maybe_basename ;
54+ char * trimmed , * prefixed_path ;
55+
5556 while (!(flags & KEEP_TRAILING_SLASH ) &&
5657 to_copy > 0 && is_dir_sep (pathspec [i ][to_copy - 1 ]))
5758 to_copy -- ;
5859
59- it = xmemdupz (pathspec [i ], to_copy );
60- if (flags & DUP_BASENAME ) {
61- result [i ] = xstrdup (basename (it ));
62- free (it );
63- } else {
64- result [i ] = it ;
65- }
66- }
67- result [count ] = NULL ;
60+ trimmed = xmemdupz (pathspec [i ], to_copy );
61+ maybe_basename = (flags & DUP_BASENAME ) ? basename (trimmed ) : trimmed ;
62+ prefixed_path = prefix_path (prefix , prefixlen , maybe_basename );
63+ strvec_push (out , prefixed_path );
6864
69- /* Prefix the pathspec and free the old intermediate strings */
70- for (i = 0 ; i < count ; i ++ ) {
71- const char * match = prefix_path (prefix , prefixlen , result [i ]);
72- free ((char * ) result [i ]);
73- result [i ] = match ;
65+ free (prefixed_path );
66+ free (trimmed );
7467 }
75-
76- return result ;
7768}
7869
7970static char * add_slash (const char * path )
@@ -176,7 +167,10 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
176167 OPT_BOOL (0 , "sparse" , & ignore_sparse , N_ ("allow updating entries outside of the sparse-checkout cone" )),
177168 OPT_END (),
178169 };
179- const char * * source , * * destination , * * dest_path , * * submodule_gitfile ;
170+ struct strvec sources = STRVEC_INIT ;
171+ struct strvec dest_paths = STRVEC_INIT ;
172+ struct strvec destinations = STRVEC_INIT ;
173+ const char * * submodule_gitfile ;
180174 char * dst_w_slash = NULL ;
181175 const char * * src_dir = NULL ;
182176 int src_dir_nr = 0 , src_dir_alloc = 0 ;
@@ -201,7 +195,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
201195 if (repo_read_index (the_repository ) < 0 )
202196 die (_ ("index file corrupt" ));
203197
204- source = internal_prefix_pathspec (prefix , argv , argc , 0 );
198+ internal_prefix_pathspec (& sources , prefix , argv , argc , 0 );
205199 CALLOC_ARRAY (modes , argc );
206200
207201 /*
@@ -212,41 +206,39 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
212206 flags = KEEP_TRAILING_SLASH ;
213207 if (argc == 1 && is_directory (argv [0 ]) && !is_directory (argv [1 ]))
214208 flags = 0 ;
215- dest_path = internal_prefix_pathspec (prefix , argv + argc , 1 , flags );
216- dst_w_slash = add_slash (dest_path [0 ]);
209+ internal_prefix_pathspec (& dest_paths , prefix , argv + argc , 1 , flags );
210+ dst_w_slash = add_slash (dest_paths . v [0 ]);
217211 submodule_gitfile = xcalloc (argc , sizeof (char * ));
218212
219- if (dest_path [0 ][0 ] == '\0' )
213+ if (dest_paths . v [0 ][0 ] == '\0' )
220214 /* special case: "." was normalized to "" */
221- destination = internal_prefix_pathspec (dest_path [0 ], argv , argc , DUP_BASENAME );
222- else if (!lstat (dest_path [0 ], & st ) &&
223- S_ISDIR (st .st_mode )) {
224- destination = internal_prefix_pathspec (dst_w_slash , argv , argc , DUP_BASENAME );
215+ internal_prefix_pathspec (& destinations , dest_paths .v [0 ], argv , argc , DUP_BASENAME );
216+ else if (!lstat (dest_paths .v [0 ], & st ) && S_ISDIR (st .st_mode )) {
217+ internal_prefix_pathspec (& destinations , dst_w_slash , argv , argc , DUP_BASENAME );
218+ } else if (!path_in_sparse_checkout (dst_w_slash , the_repository -> index ) &&
219+ empty_dir_has_sparse_contents (dst_w_slash )) {
220+ internal_prefix_pathspec (& destinations , dst_w_slash , argv , argc , DUP_BASENAME );
221+ dst_mode = SKIP_WORKTREE_DIR ;
222+ } else if (argc != 1 ) {
223+ die (_ ("destination '%s' is not a directory" ), dest_paths .v [0 ]);
225224 } else {
226- if (!path_in_sparse_checkout (dst_w_slash , the_repository -> index ) &&
227- empty_dir_has_sparse_contents (dst_w_slash )) {
228- destination = internal_prefix_pathspec (dst_w_slash , argv , argc , DUP_BASENAME );
229- dst_mode = SKIP_WORKTREE_DIR ;
230- } else if (argc != 1 ) {
231- die (_ ("destination '%s' is not a directory" ), dest_path [0 ]);
232- } else {
233- destination = dest_path ;
234- /*
235- * <destination> is a file outside of sparse-checkout
236- * cone. Insist on cone mode here for backward
237- * compatibility. We don't want dst_mode to be assigned
238- * for a file when the repo is using no-cone mode (which
239- * is deprecated at this point) sparse-checkout. As
240- * SPARSE here is only considering cone-mode situation.
241- */
242- if (!path_in_cone_mode_sparse_checkout (destination [0 ], the_repository -> index ))
243- dst_mode = SPARSE ;
244- }
225+ strvec_pushv (& destinations , dest_paths .v );
226+
227+ /*
228+ * <destination> is a file outside of sparse-checkout
229+ * cone. Insist on cone mode here for backward
230+ * compatibility. We don't want dst_mode to be assigned
231+ * for a file when the repo is using no-cone mode (which
232+ * is deprecated at this point) sparse-checkout. As
233+ * SPARSE here is only considering cone-mode situation.
234+ */
235+ if (!path_in_cone_mode_sparse_checkout (destinations .v [0 ], the_repository -> index ))
236+ dst_mode = SPARSE ;
245237 }
246238
247239 /* Checking */
248240 for (i = 0 ; i < argc ; i ++ ) {
249- const char * src = source [i ], * dst = destination [i ];
241+ const char * src = sources . v [i ], * dst = destinations . v [i ];
250242 int length ;
251243 const char * bad = NULL ;
252244 int skip_sparse = 0 ;
@@ -330,8 +322,6 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
330322 src_dir [src_dir_nr ++ ] = src ;
331323
332324 n = argc + last - first ;
333- REALLOC_ARRAY (source , n );
334- REALLOC_ARRAY (destination , n );
335325 REALLOC_ARRAY (modes , n );
336326 REALLOC_ARRAY (submodule_gitfile , n );
337327
@@ -341,12 +331,16 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
341331 for (j = 0 ; j < last - first ; j ++ ) {
342332 const struct cache_entry * ce = the_repository -> index -> cache [first + j ];
343333 const char * path = ce -> name ;
344- source [argc + j ] = path ;
345- destination [argc + j ] =
346- prefix_path (dst_with_slash , dst_with_slash_len , path + length + 1 );
334+ char * prefixed_path = prefix_path (dst_with_slash , dst_with_slash_len , path + length + 1 );
335+
336+ strvec_push (& sources , path );
337+ strvec_push (& destinations , prefixed_path );
338+
347339 memset (modes + argc + j , 0 , sizeof (enum update_mode ));
348340 modes [argc + j ] |= ce_skip_worktree (ce ) ? SPARSE : INDEX ;
349341 submodule_gitfile [argc + j ] = NULL ;
342+
343+ free (prefixed_path );
350344 }
351345
352346 free (dst_with_slash );
@@ -430,8 +424,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
430424remove_entry :
431425 if (-- argc > 0 ) {
432426 int n = argc - i ;
433- MOVE_ARRAY ( source + i , source + i + 1 , n );
434- MOVE_ARRAY ( destination + i , destination + i + 1 , n );
427+ strvec_remove ( & sources , i );
428+ strvec_remove ( & destinations , i );
435429 MOVE_ARRAY (modes + i , modes + i + 1 , n );
436430 MOVE_ARRAY (submodule_gitfile + i ,
437431 submodule_gitfile + i + 1 , n );
@@ -448,7 +442,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
448442 }
449443
450444 for (i = 0 ; i < argc ; i ++ ) {
451- const char * src = source [i ], * dst = destination [i ];
445+ const char * src = sources . v [i ], * dst = destinations . v [i ];
452446 enum update_mode mode = modes [i ];
453447 int pos ;
454448 int sparse_and_dirty = 0 ;
@@ -576,8 +570,9 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
576570 string_list_clear (& src_for_dst , 0 );
577571 string_list_clear (& dirty_paths , 0 );
578572 string_list_clear (& only_match_skip_worktree , 0 );
579- UNLEAK (source );
580- UNLEAK (dest_path );
573+ strvec_clear (& sources );
574+ strvec_clear (& dest_paths );
575+ strvec_clear (& destinations );
581576 free (submodule_gitfile );
582577 free (modes );
583578 return ret ;
0 commit comments