@@ -416,48 +416,190 @@ static char *squash_slash(char *name)
416
416
return name ;
417
417
}
418
418
419
- static char * find_name (const char * line , char * def , int p_value , int terminate )
419
+ static char * find_name_gnu (const char * line , char * def , int p_value )
420
420
{
421
- int len ;
422
- const char * start = NULL ;
421
+ struct strbuf name = STRBUF_INIT ;
422
+ char * cp ;
423
423
424
- if (p_value == 0 )
425
- start = line ;
424
+ /*
425
+ * Proposed "new-style" GNU patch/diff format; see
426
+ * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
427
+ */
428
+ if (unquote_c_style (& name , line , NULL )) {
429
+ strbuf_release (& name );
430
+ return NULL ;
431
+ }
426
432
427
- if (* line == '"' ) {
428
- struct strbuf name = STRBUF_INIT ;
433
+ for (cp = name .buf ; p_value ; p_value -- ) {
434
+ cp = strchr (cp , '/' );
435
+ if (!cp ) {
436
+ strbuf_release (& name );
437
+ return NULL ;
438
+ }
439
+ cp ++ ;
440
+ }
429
441
430
- /*
431
- * Proposed "new-style" GNU patch/diff format; see
432
- * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
433
- */
434
- if (!unquote_c_style (& name , line , NULL )) {
435
- char * cp ;
442
+ /* name can later be freed, so we need
443
+ * to memmove, not just return cp
444
+ */
445
+ strbuf_remove (& name , 0 , cp - name .buf );
446
+ free (def );
447
+ if (root )
448
+ strbuf_insert (& name , 0 , root , root_len );
449
+ return squash_slash (strbuf_detach (& name , NULL ));
450
+ }
436
451
437
- for (cp = name .buf ; p_value ; p_value -- ) {
438
- cp = strchr (cp , '/' );
439
- if (!cp )
440
- break ;
441
- cp ++ ;
442
- }
443
- if (cp ) {
444
- /* name can later be freed, so we need
445
- * to memmove, not just return cp
446
- */
447
- strbuf_remove (& name , 0 , cp - name .buf );
448
- free (def );
449
- if (root )
450
- strbuf_insert (& name , 0 , root , root_len );
451
- return squash_slash (strbuf_detach (& name , NULL ));
452
- }
453
- }
454
- strbuf_release (& name );
452
+ static size_t tz_len (const char * line , size_t len )
453
+ {
454
+ const char * tz , * p ;
455
+
456
+ if (len < strlen (" +0500" ) || line [len - strlen (" +0500" )] != ' ' )
457
+ return 0 ;
458
+ tz = line + len - strlen (" +0500" );
459
+
460
+ if (tz [1 ] != '+' && tz [1 ] != '-' )
461
+ return 0 ;
462
+
463
+ for (p = tz + 2 ; p != line + len ; p ++ )
464
+ if (!isdigit (* p ))
465
+ return 0 ;
466
+
467
+ return line + len - tz ;
468
+ }
469
+
470
+ static size_t date_len (const char * line , size_t len )
471
+ {
472
+ const char * date , * p ;
473
+
474
+ if (len < strlen ("72-02-05" ) || line [len - strlen ("-05" )] != '-' )
475
+ return 0 ;
476
+ p = date = line + len - strlen ("72-02-05" );
477
+
478
+ if (!isdigit (* p ++ ) || !isdigit (* p ++ ) || * p ++ != '-' ||
479
+ !isdigit (* p ++ ) || !isdigit (* p ++ ) || * p ++ != '-' ||
480
+ !isdigit (* p ++ ) || !isdigit (* p ++ )) /* Not a date. */
481
+ return 0 ;
482
+
483
+ if (date - line >= strlen ("19" ) &&
484
+ isdigit (date [-1 ]) && isdigit (date [-2 ])) /* 4-digit year */
485
+ date -= strlen ("19" );
486
+
487
+ return line + len - date ;
488
+ }
489
+
490
+ static size_t short_time_len (const char * line , size_t len )
491
+ {
492
+ const char * time , * p ;
493
+
494
+ if (len < strlen (" 07:01:32" ) || line [len - strlen (":32" )] != ':' )
495
+ return 0 ;
496
+ p = time = line + len - strlen (" 07:01:32" );
497
+
498
+ /* Permit 1-digit hours? */
499
+ if (* p ++ != ' ' ||
500
+ !isdigit (* p ++ ) || !isdigit (* p ++ ) || * p ++ != ':' ||
501
+ !isdigit (* p ++ ) || !isdigit (* p ++ ) || * p ++ != ':' ||
502
+ !isdigit (* p ++ ) || !isdigit (* p ++ )) /* Not a time. */
503
+ return 0 ;
504
+
505
+ return line + len - time ;
506
+ }
507
+
508
+ static size_t fractional_time_len (const char * line , size_t len )
509
+ {
510
+ const char * p ;
511
+ size_t n ;
512
+
513
+ /* Expected format: 19:41:17.620000023 */
514
+ if (!len || !isdigit (line [len - 1 ]))
515
+ return 0 ;
516
+ p = line + len - 1 ;
517
+
518
+ /* Fractional seconds. */
519
+ while (p > line && isdigit (* p ))
520
+ p -- ;
521
+ if (* p != '.' )
522
+ return 0 ;
523
+
524
+ /* Hours, minutes, and whole seconds. */
525
+ n = short_time_len (line , p - line );
526
+ if (!n )
527
+ return 0 ;
528
+
529
+ return line + len - p + n ;
530
+ }
531
+
532
+ static size_t trailing_spaces_len (const char * line , size_t len )
533
+ {
534
+ const char * p ;
535
+
536
+ /* Expected format: ' ' x (1 or more) */
537
+ if (!len || line [len - 1 ] != ' ' )
538
+ return 0 ;
539
+
540
+ p = line + len ;
541
+ while (p != line ) {
542
+ p -- ;
543
+ if (* p != ' ' )
544
+ return line + len - (p + 1 );
455
545
}
456
546
457
- for (;;) {
547
+ /* All spaces! */
548
+ return len ;
549
+ }
550
+
551
+ static size_t diff_timestamp_len (const char * line , size_t len )
552
+ {
553
+ const char * end = line + len ;
554
+ size_t n ;
555
+
556
+ /*
557
+ * Posix: 2010-07-05 19:41:17
558
+ * GNU: 2010-07-05 19:41:17.620000023 -0500
559
+ */
560
+
561
+ if (!isdigit (end [-1 ]))
562
+ return 0 ;
563
+
564
+ n = tz_len (line , end - line );
565
+ end -= n ;
566
+
567
+ n = short_time_len (line , end - line );
568
+ if (!n )
569
+ n = fractional_time_len (line , end - line );
570
+ end -= n ;
571
+
572
+ n = date_len (line , end - line );
573
+ if (!n ) /* No date. Too bad. */
574
+ return 0 ;
575
+ end -= n ;
576
+
577
+ if (end == line ) /* No space before date. */
578
+ return 0 ;
579
+ if (end [-1 ] == '\t' ) { /* Success! */
580
+ end -- ;
581
+ return line + len - end ;
582
+ }
583
+ if (end [-1 ] != ' ' ) /* No space before date. */
584
+ return 0 ;
585
+
586
+ /* Whitespace damage. */
587
+ end -= trailing_spaces_len (line , end - line );
588
+ return line + len - end ;
589
+ }
590
+
591
+ static char * find_name_common (const char * line , char * def , int p_value ,
592
+ const char * end , int terminate )
593
+ {
594
+ int len ;
595
+ const char * start = NULL ;
596
+
597
+ if (p_value == 0 )
598
+ start = line ;
599
+ while (line != end ) {
458
600
char c = * line ;
459
601
460
- if (isspace (c )) {
602
+ if (! end && isspace (c )) {
461
603
if (c == '\n' )
462
604
break ;
463
605
if (name_terminate (start , line - start , c , terminate ))
@@ -497,6 +639,37 @@ static char *find_name(const char *line, char *def, int p_value, int terminate)
497
639
return squash_slash (xmemdupz (start , len ));
498
640
}
499
641
642
+ static char * find_name (const char * line , char * def , int p_value , int terminate )
643
+ {
644
+ if (* line == '"' ) {
645
+ char * name = find_name_gnu (line , def , p_value );
646
+ if (name )
647
+ return name ;
648
+ }
649
+
650
+ return find_name_common (line , def , p_value , NULL , terminate );
651
+ }
652
+
653
+ static char * find_name_traditional (const char * line , char * def , int p_value )
654
+ {
655
+ size_t len = strlen (line );
656
+ size_t date_len ;
657
+
658
+ if (* line == '"' ) {
659
+ char * name = find_name_gnu (line , def , p_value );
660
+ if (name )
661
+ return name ;
662
+ }
663
+
664
+ len = strchrnul (line , '\n' ) - line ;
665
+ date_len = diff_timestamp_len (line , len );
666
+ if (!date_len )
667
+ return find_name_common (line , def , p_value , NULL , TERM_TAB );
668
+ len -= date_len ;
669
+
670
+ return find_name_common (line , def , p_value , line + len , 0 );
671
+ }
672
+
500
673
static int count_slashes (const char * cp )
501
674
{
502
675
int cnt = 0 ;
@@ -519,7 +692,7 @@ static int guess_p_value(const char *nameline)
519
692
520
693
if (is_dev_null (nameline ))
521
694
return -1 ;
522
- name = find_name (nameline , NULL , 0 , TERM_SPACE | TERM_TAB );
695
+ name = find_name_traditional (nameline , NULL , 0 );
523
696
if (!name )
524
697
return -1 ;
525
698
cp = strchr (name , '/' );
@@ -638,16 +811,16 @@ static void parse_traditional_patch(const char *first, const char *second, struc
638
811
if (is_dev_null (first )) {
639
812
patch -> is_new = 1 ;
640
813
patch -> is_delete = 0 ;
641
- name = find_name (second , NULL , p_value , TERM_SPACE | TERM_TAB );
814
+ name = find_name_traditional (second , NULL , p_value );
642
815
patch -> new_name = name ;
643
816
} else if (is_dev_null (second )) {
644
817
patch -> is_new = 0 ;
645
818
patch -> is_delete = 1 ;
646
- name = find_name (first , NULL , p_value , TERM_SPACE | TERM_TAB );
819
+ name = find_name_traditional (first , NULL , p_value );
647
820
patch -> old_name = name ;
648
821
} else {
649
- name = find_name (first , NULL , p_value , TERM_SPACE | TERM_TAB );
650
- name = find_name (second , name , p_value , TERM_SPACE | TERM_TAB );
822
+ name = find_name_traditional (first , NULL , p_value );
823
+ name = find_name_traditional (second , name , p_value );
651
824
if (has_epoch_timestamp (first )) {
652
825
patch -> is_new = 1 ;
653
826
patch -> is_delete = 0 ;
0 commit comments