449
return squash_slash(strbuf_detach(&name, NULL));
450
}
451
452
-static char *find_name(const char *line, char *def, int p_value, int terminate)
452
+static size_t tz_len(const char *line, size_t len)
453
{
454
- int len;
455
- const char *start = NULL;
454
+ const char *tz, *p;
455
457
- if (*line == '"') {
458
- char *name = find_name_gnu(line, def, p_value);
459
- if (name)
460
- return name;
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);
545
}
546
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;
465
- for (;;) {
599
+ while (line != end) {
600
char c = *line;
601
468
- if (isspace(c)) {
602
+ if (!end && isspace(c)) {
603
if (c == '\n')
604
break;
605
if (name_terminate(start, line-start, c, terminate))
639
return squash_slash(xmemdupz(start, len));
640
}
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
+
673
static int count_slashes(const char *cp)
674
{
675
int cnt = 0;
692
693
if (is_dev_null(nameline))
694
return -1;
530
- name = find_name(nameline, NULL, 0, TERM_SPACE | TERM_TAB);
695
+ name = find_name_traditional(nameline, NULL, 0);
696
if (!name)
697
return -1;
698
cp = strchr(name, '/');
811
if (is_dev_null(first)) {
812
patch->is_new = 1;
813
patch->is_delete = 0;
649
- name = find_name(second, NULL, p_value, TERM_SPACE | TERM_TAB);
814
+ name = find_name_traditional(second, NULL, p_value);
815
patch->new_name = name;
816
} else if (is_dev_null(second)) {
817
patch->is_new = 0;
818
patch->is_delete = 1;
654
- name = find_name(first, NULL, p_value, TERM_SPACE | TERM_TAB);
819
+ name = find_name_traditional(first, NULL, p_value);
820
patch->old_name = name;
821
} else {
657
- name = find_name(first, NULL, p_value, TERM_SPACE | TERM_TAB);
658
- 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);
824
if (has_epoch_timestamp(first)) {
825
patch->is_new = 1;
826
patch->is_delete = 0;