11#include "cache.h"
22#include "attr.h"
3+ #include "run-command.h"
34
45/*
56 * convert.c - convert a file when checking it out and checking it in.
@@ -203,10 +204,152 @@ static char *crlf_to_worktree(const char *path, const char *src, unsigned long *
203204static void setup_convert_check (struct git_attr_check * check )
204205{
205206 static struct git_attr * attr_crlf ;
207+ static struct git_attr * attr_ident ;
206208
207- if (!attr_crlf )
209+ if (!attr_crlf ) {
208210 attr_crlf = git_attr ("crlf" , 4 );
209- check -> attr = attr_crlf ;
211+ attr_ident = git_attr ("ident" , 5 );
212+ }
213+ check [0 ].attr = attr_crlf ;
214+ check [1 ].attr = attr_ident ;
215+ }
216+
217+ static int count_ident (const char * cp , unsigned long size )
218+ {
219+ /*
220+ * "$ident: 0000000000000000000000000000000000000000 $" <=> "$ident$"
221+ */
222+ int cnt = 0 ;
223+ char ch ;
224+
225+ while (size ) {
226+ ch = * cp ++ ;
227+ size -- ;
228+ if (ch != '$' )
229+ continue ;
230+ if (size < 6 )
231+ break ;
232+ if (memcmp ("ident" , cp , 5 ))
233+ continue ;
234+ ch = cp [5 ];
235+ cp += 6 ;
236+ size -= 6 ;
237+ if (ch == '$' )
238+ cnt ++ ; /* $ident$ */
239+ if (ch != ':' )
240+ continue ;
241+
242+ /*
243+ * "$ident: ... "; scan up to the closing dollar sign and discard.
244+ */
245+ while (size ) {
246+ ch = * cp ++ ;
247+ size -- ;
248+ if (ch == '$' ) {
249+ cnt ++ ;
250+ break ;
251+ }
252+ }
253+ }
254+ return cnt ;
255+ }
256+
257+ static char * ident_to_git (const char * path , const char * src , unsigned long * sizep , int ident )
258+ {
259+ int cnt ;
260+ unsigned long size ;
261+ char * dst , * buf ;
262+
263+ if (!ident )
264+ return NULL ;
265+ size = * sizep ;
266+ cnt = count_ident (src , size );
267+ if (!cnt )
268+ return NULL ;
269+ buf = xmalloc (size );
270+
271+ for (dst = buf ; size ; size -- ) {
272+ char ch = * src ++ ;
273+ * dst ++ = ch ;
274+ if ((ch == '$' ) && (6 <= size ) &&
275+ !memcmp ("ident:" , src , 6 )) {
276+ unsigned long rem = size - 6 ;
277+ const char * cp = src + 6 ;
278+ do {
279+ ch = * cp ++ ;
280+ if (ch == '$' )
281+ break ;
282+ rem -- ;
283+ } while (rem );
284+ if (!rem )
285+ continue ;
286+ memcpy (dst , "ident$" , 6 );
287+ dst += 6 ;
288+ size -= (cp - src );
289+ src = cp ;
290+ }
291+ }
292+
293+ * sizep = dst - buf ;
294+ return buf ;
295+ }
296+
297+ static char * ident_to_worktree (const char * path , const char * src , unsigned long * sizep , int ident )
298+ {
299+ int cnt ;
300+ unsigned long size ;
301+ char * dst , * buf ;
302+ unsigned char sha1 [20 ];
303+
304+ if (!ident )
305+ return NULL ;
306+
307+ size = * sizep ;
308+ cnt = count_ident (src , size );
309+ if (!cnt )
310+ return NULL ;
311+
312+ hash_sha1_file (src , size , "blob" , sha1 );
313+ buf = xmalloc (size + cnt * 43 );
314+
315+ for (dst = buf ; size ; size -- ) {
316+ const char * cp ;
317+ char ch = * src ++ ;
318+ * dst ++ = ch ;
319+ if ((ch != '$' ) || (size < 6 ) || memcmp ("ident" , src , 5 ))
320+ continue ;
321+
322+ if (src [5 ] == ':' ) {
323+ /* discard up to but not including the closing $ */
324+ unsigned long rem = size - 6 ;
325+ cp = src + 6 ;
326+ do {
327+ ch = * cp ++ ;
328+ if (ch == '$' )
329+ break ;
330+ rem -- ;
331+ } while (rem );
332+ if (!rem )
333+ continue ;
334+ size -= (cp - src );
335+ } else if (src [5 ] == '$' )
336+ cp = src + 5 ;
337+ else
338+ continue ;
339+
340+ memcpy (dst , "ident: " , 7 );
341+ dst += 7 ;
342+ memcpy (dst , sha1_to_hex (sha1 ), 40 );
343+ dst += 40 ;
344+ * dst ++ = ' ' ;
345+ size -= (cp - src );
346+ src = cp ;
347+ * dst ++ = * src ++ ;
348+ size -- ;
349+ }
350+
351+ * sizep = dst - buf ;
352+ return buf ;
210353}
211354
212355static int git_path_check_crlf (const char * path , struct git_attr_check * check )
@@ -224,26 +367,57 @@ static int git_path_check_crlf(const char *path, struct git_attr_check *check)
224367 return CRLF_GUESS ;
225368}
226369
370+ static int git_path_check_ident (const char * path , struct git_attr_check * check )
371+ {
372+ const char * value = check -> value ;
373+
374+ return !!ATTR_TRUE (value );
375+ }
376+
227377char * convert_to_git (const char * path , const char * src , unsigned long * sizep )
228378{
229- struct git_attr_check check [1 ];
379+ struct git_attr_check check [2 ];
230380 int crlf = CRLF_GUESS ;
381+ int ident = 0 ;
382+ char * buf , * buf2 ;
231383
232384 setup_convert_check (check );
233- if (!git_checkattr (path , 1 , check )) {
234- crlf = git_path_check_crlf (path , check );
385+ if (!git_checkattr (path , ARRAY_SIZE (check ), check )) {
386+ crlf = git_path_check_crlf (path , check + 0 );
387+ ident = git_path_check_ident (path , check + 1 );
388+ }
389+
390+ buf = crlf_to_git (path , src , sizep , crlf );
391+
392+ buf2 = ident_to_git (path , buf ? buf : src , sizep , ident );
393+ if (buf2 ) {
394+ free (buf );
395+ buf = buf2 ;
235396 }
236- return crlf_to_git (path , src , sizep , crlf );
397+
398+ return buf ;
237399}
238400
239401char * convert_to_working_tree (const char * path , const char * src , unsigned long * sizep )
240402{
241- struct git_attr_check check [1 ];
403+ struct git_attr_check check [2 ];
242404 int crlf = CRLF_GUESS ;
405+ int ident = 0 ;
406+ char * buf , * buf2 ;
243407
244408 setup_convert_check (check );
245- if (!git_checkattr (path , 1 , check )) {
246- crlf = git_path_check_crlf (path , check );
409+ if (!git_checkattr (path , ARRAY_SIZE (check ), check )) {
410+ crlf = git_path_check_crlf (path , check + 0 );
411+ ident = git_path_check_ident (path , check + 1 );
247412 }
248- return crlf_to_worktree (path , src , sizep , crlf );
413+
414+ buf = ident_to_worktree (path , src , sizep , ident );
415+
416+ buf2 = crlf_to_worktree (path , buf ? buf : src , sizep , crlf );
417+ if (buf2 ) {
418+ free (buf );
419+ buf = buf2 ;
420+ }
421+
422+ return buf ;
249423}
0 commit comments