Fossil SCM
Add function print_ref to sanitize branch and tag names in accordance with https://git-scm.com/docs/git-check-ref-format Use this rather than simply replacing non alpha or numeric chars for branch and tag names when exporting.
Commit
abc87ccdd5aac7b952a8121ab46c715a52900e5f
Parent
4a51461e96e0a4b…
1 file changed
+64
-16
+64
-16
| --- src/export.c | ||
| +++ src/export.c | ||
| @@ -161,10 +161,68 @@ | ||
| 161 | 161 | printf(" %s <%s>", zName, zEmail); |
| 162 | 162 | free(zName); |
| 163 | 163 | free(zEmail); |
| 164 | 164 | db_reset(&q); |
| 165 | 165 | } |
| 166 | + | |
| 167 | +#define REFREPLACEMENT '_' | |
| 168 | + | |
| 169 | +/* | |
| 170 | +** Output a sanitized git named reference. | |
| 171 | +** https://git-scm.com/docs/git-check-ref-format | |
| 172 | +** This implementation assumes we are only printing | |
| 173 | +** the branch or tag part of the reference. | |
| 174 | +*/ | |
| 175 | +static void print_ref(const char *zRef){ | |
| 176 | + char *zEncoded = mprintf("%s", zRef); | |
| 177 | + int i, w; | |
| 178 | + if (zEncoded[0]=='@' && zEncoded[1]=='\0'){ | |
| 179 | + putchar(REFREPLACEMENT); | |
| 180 | + return; | |
| 181 | + } | |
| 182 | + for(i=0, w=0; zEncoded[i]; i++, w++){ | |
| 183 | + if( i!=0 ){ /* Two letter tests */ | |
| 184 | + if( (zEncoded[i-1]=='.' && zEncoded[i]=='.') || | |
| 185 | + (zEncoded[i-1]=='@' && zEncoded[i]=='{') ){ | |
| 186 | + zEncoded[w]=zEncoded[w-1]=REFREPLACEMENT; | |
| 187 | + continue; | |
| 188 | + } | |
| 189 | + if( zEncoded[i-1]=='/' && zEncoded[i]=='/' ){ | |
| 190 | + w--; /* Normalise to a single / by rolling back w */ | |
| 191 | + continue; | |
| 192 | + } | |
| 193 | + } | |
| 194 | + /* No control characters */ | |
| 195 | + if( (unsigned)zEncoded[i]<0x20 || zEncoded[i]==0x7f ){ | |
| 196 | + zEncoded[w]=REFREPLACEMENT; | |
| 197 | + continue; | |
| 198 | + } | |
| 199 | + switch( zEncoded[i] ){ | |
| 200 | + case ' ': | |
| 201 | + case '^': | |
| 202 | + case ':': | |
| 203 | + case '?': | |
| 204 | + case '*': | |
| 205 | + case '[': | |
| 206 | + case '\\': | |
| 207 | + zEncoded[w]=REFREPLACEMENT; | |
| 208 | + break; | |
| 209 | + } | |
| 210 | + } | |
| 211 | + /* Cannot begin with a . or / */ | |
| 212 | + if( zEncoded[0]=='.' || zEncoded[0] == '/' ) zEncoded[0]=REFREPLACEMENT; | |
| 213 | + if( i>0 ){ | |
| 214 | + i--; w--; | |
| 215 | + /* Or end with a . or / */ | |
| 216 | + if( zEncoded[i]=='.' || zEncoded[i] == '/' ) zEncoded[w]=REFREPLACEMENT; | |
| 217 | + /* Cannot end with .lock */ | |
| 218 | + if ( i>4 && strcmp((zEncoded+i)-5, ".lock")==0 ) | |
| 219 | + memset((zEncoded+w)-5, REFREPLACEMENT, 5); | |
| 220 | + } | |
| 221 | + printf("%s", zEncoded); | |
| 222 | + free(zEncoded); | |
| 223 | +} | |
| 166 | 224 | |
| 167 | 225 | #define BLOBMARK(rid) ((rid) * 2) |
| 168 | 226 | #define COMMITMARK(rid) ((rid) * 2 + 1) |
| 169 | 227 | |
| 170 | 228 | /* |
| @@ -547,26 +605,22 @@ | ||
| 547 | 605 | const char *zSecondsSince1970 = db_column_text(&q, 0); |
| 548 | 606 | int ckinId = db_column_int(&q, 1); |
| 549 | 607 | const char *zComment = db_column_text(&q, 2); |
| 550 | 608 | const char *zUser = db_column_text(&q, 3); |
| 551 | 609 | const char *zBranch = db_column_text(&q, 4); |
| 552 | - char *zBr; | |
| 553 | 610 | char *zMark; |
| 554 | 611 | |
| 555 | 612 | bag_insert(&vers, ckinId); |
| 556 | 613 | db_bind_int(&q2, ":rid", ckinId); |
| 557 | 614 | db_step(&q2); |
| 558 | 615 | db_reset(&q2); |
| 559 | 616 | if( zBranch==0 ) zBranch = "trunk"; |
| 560 | - zBr = mprintf("%s", zBranch); | |
| 561 | - for(i=0; zBr[i]; i++){ | |
| 562 | - if( !fossil_isalnum(zBr[i]) ) zBr[i] = '_'; | |
| 563 | - } | |
| 564 | 617 | zMark = mark_name_from_rid(ckinId, &unused_mark); |
| 565 | - printf("commit refs/heads/%s\nmark %s\n", zBr, zMark); | |
| 618 | + printf("commit refs/heads/"); | |
| 619 | + print_ref(zBranch); | |
| 620 | + printf("\nmark %s\n", zMark); | |
| 566 | 621 | free(zMark); |
| 567 | - free(zBr); | |
| 568 | 622 | printf("committer"); |
| 569 | 623 | print_person(zUser); |
| 570 | 624 | printf(" %s +0000\n", zSecondsSince1970); |
| 571 | 625 | if( zComment==0 ) zComment = "null comment"; |
| 572 | 626 | printf("data %d\n%s\n", (int)strlen(zComment), zComment); |
| @@ -637,30 +691,24 @@ | ||
| 637 | 691 | " FROM tagxref JOIN tag USING(tagid)" |
| 638 | 692 | " WHERE tagtype=1 AND tagname GLOB 'sym-*'" |
| 639 | 693 | ); |
| 640 | 694 | while( db_step(&q)==SQLITE_ROW ){ |
| 641 | 695 | const char *zTagname = db_column_text(&q, 0); |
| 642 | - char *zEncoded = 0; | |
| 643 | 696 | int rid = db_column_int(&q, 1); |
| 644 | 697 | char *zMark = mark_name_from_rid(rid, &unused_mark); |
| 645 | 698 | const char *zSecSince1970 = db_column_text(&q, 2); |
| 646 | 699 | const char *zUser = db_column_text(&q, 3); |
| 647 | - int i; | |
| 648 | 700 | if( rid==0 || !bag_find(&vers, rid) ) continue; |
| 649 | 701 | zTagname += 4; |
| 650 | - zEncoded = mprintf("%s", zTagname); | |
| 651 | - for(i=0; zEncoded[i]; i++){ | |
| 652 | - if( !fossil_isalnum(zEncoded[i]) ) zEncoded[i] = '_'; | |
| 653 | - } | |
| 654 | - printf("tag %s\n", zEncoded); | |
| 655 | - printf("from %s\n", zMark); | |
| 702 | + printf("tag "); | |
| 703 | + print_ref(zTagname); | |
| 704 | + printf("\nfrom %s\n", zMark); | |
| 656 | 705 | free(zMark); |
| 657 | 706 | printf("tagger"); |
| 658 | 707 | print_person(zUser); |
| 659 | 708 | printf(" %s +0000\n", zSecSince1970); |
| 660 | 709 | printf("data 0\n"); |
| 661 | - fossil_free(zEncoded); | |
| 662 | 710 | } |
| 663 | 711 | db_finalize(&q); |
| 664 | 712 | |
| 665 | 713 | if( markfile_out!=0 ){ |
| 666 | 714 | FILE *f; |
| 667 | 715 |
| --- src/export.c | |
| +++ src/export.c | |
| @@ -161,10 +161,68 @@ | |
| 161 | printf(" %s <%s>", zName, zEmail); |
| 162 | free(zName); |
| 163 | free(zEmail); |
| 164 | db_reset(&q); |
| 165 | } |
| 166 | |
| 167 | #define BLOBMARK(rid) ((rid) * 2) |
| 168 | #define COMMITMARK(rid) ((rid) * 2 + 1) |
| 169 | |
| 170 | /* |
| @@ -547,26 +605,22 @@ | |
| 547 | const char *zSecondsSince1970 = db_column_text(&q, 0); |
| 548 | int ckinId = db_column_int(&q, 1); |
| 549 | const char *zComment = db_column_text(&q, 2); |
| 550 | const char *zUser = db_column_text(&q, 3); |
| 551 | const char *zBranch = db_column_text(&q, 4); |
| 552 | char *zBr; |
| 553 | char *zMark; |
| 554 | |
| 555 | bag_insert(&vers, ckinId); |
| 556 | db_bind_int(&q2, ":rid", ckinId); |
| 557 | db_step(&q2); |
| 558 | db_reset(&q2); |
| 559 | if( zBranch==0 ) zBranch = "trunk"; |
| 560 | zBr = mprintf("%s", zBranch); |
| 561 | for(i=0; zBr[i]; i++){ |
| 562 | if( !fossil_isalnum(zBr[i]) ) zBr[i] = '_'; |
| 563 | } |
| 564 | zMark = mark_name_from_rid(ckinId, &unused_mark); |
| 565 | printf("commit refs/heads/%s\nmark %s\n", zBr, zMark); |
| 566 | free(zMark); |
| 567 | free(zBr); |
| 568 | printf("committer"); |
| 569 | print_person(zUser); |
| 570 | printf(" %s +0000\n", zSecondsSince1970); |
| 571 | if( zComment==0 ) zComment = "null comment"; |
| 572 | printf("data %d\n%s\n", (int)strlen(zComment), zComment); |
| @@ -637,30 +691,24 @@ | |
| 637 | " FROM tagxref JOIN tag USING(tagid)" |
| 638 | " WHERE tagtype=1 AND tagname GLOB 'sym-*'" |
| 639 | ); |
| 640 | while( db_step(&q)==SQLITE_ROW ){ |
| 641 | const char *zTagname = db_column_text(&q, 0); |
| 642 | char *zEncoded = 0; |
| 643 | int rid = db_column_int(&q, 1); |
| 644 | char *zMark = mark_name_from_rid(rid, &unused_mark); |
| 645 | const char *zSecSince1970 = db_column_text(&q, 2); |
| 646 | const char *zUser = db_column_text(&q, 3); |
| 647 | int i; |
| 648 | if( rid==0 || !bag_find(&vers, rid) ) continue; |
| 649 | zTagname += 4; |
| 650 | zEncoded = mprintf("%s", zTagname); |
| 651 | for(i=0; zEncoded[i]; i++){ |
| 652 | if( !fossil_isalnum(zEncoded[i]) ) zEncoded[i] = '_'; |
| 653 | } |
| 654 | printf("tag %s\n", zEncoded); |
| 655 | printf("from %s\n", zMark); |
| 656 | free(zMark); |
| 657 | printf("tagger"); |
| 658 | print_person(zUser); |
| 659 | printf(" %s +0000\n", zSecSince1970); |
| 660 | printf("data 0\n"); |
| 661 | fossil_free(zEncoded); |
| 662 | } |
| 663 | db_finalize(&q); |
| 664 | |
| 665 | if( markfile_out!=0 ){ |
| 666 | FILE *f; |
| 667 |
| --- src/export.c | |
| +++ src/export.c | |
| @@ -161,10 +161,68 @@ | |
| 161 | printf(" %s <%s>", zName, zEmail); |
| 162 | free(zName); |
| 163 | free(zEmail); |
| 164 | db_reset(&q); |
| 165 | } |
| 166 | |
| 167 | #define REFREPLACEMENT '_' |
| 168 | |
| 169 | /* |
| 170 | ** Output a sanitized git named reference. |
| 171 | ** https://git-scm.com/docs/git-check-ref-format |
| 172 | ** This implementation assumes we are only printing |
| 173 | ** the branch or tag part of the reference. |
| 174 | */ |
| 175 | static void print_ref(const char *zRef){ |
| 176 | char *zEncoded = mprintf("%s", zRef); |
| 177 | int i, w; |
| 178 | if (zEncoded[0]=='@' && zEncoded[1]=='\0'){ |
| 179 | putchar(REFREPLACEMENT); |
| 180 | return; |
| 181 | } |
| 182 | for(i=0, w=0; zEncoded[i]; i++, w++){ |
| 183 | if( i!=0 ){ /* Two letter tests */ |
| 184 | if( (zEncoded[i-1]=='.' && zEncoded[i]=='.') || |
| 185 | (zEncoded[i-1]=='@' && zEncoded[i]=='{') ){ |
| 186 | zEncoded[w]=zEncoded[w-1]=REFREPLACEMENT; |
| 187 | continue; |
| 188 | } |
| 189 | if( zEncoded[i-1]=='/' && zEncoded[i]=='/' ){ |
| 190 | w--; /* Normalise to a single / by rolling back w */ |
| 191 | continue; |
| 192 | } |
| 193 | } |
| 194 | /* No control characters */ |
| 195 | if( (unsigned)zEncoded[i]<0x20 || zEncoded[i]==0x7f ){ |
| 196 | zEncoded[w]=REFREPLACEMENT; |
| 197 | continue; |
| 198 | } |
| 199 | switch( zEncoded[i] ){ |
| 200 | case ' ': |
| 201 | case '^': |
| 202 | case ':': |
| 203 | case '?': |
| 204 | case '*': |
| 205 | case '[': |
| 206 | case '\\': |
| 207 | zEncoded[w]=REFREPLACEMENT; |
| 208 | break; |
| 209 | } |
| 210 | } |
| 211 | /* Cannot begin with a . or / */ |
| 212 | if( zEncoded[0]=='.' || zEncoded[0] == '/' ) zEncoded[0]=REFREPLACEMENT; |
| 213 | if( i>0 ){ |
| 214 | i--; w--; |
| 215 | /* Or end with a . or / */ |
| 216 | if( zEncoded[i]=='.' || zEncoded[i] == '/' ) zEncoded[w]=REFREPLACEMENT; |
| 217 | /* Cannot end with .lock */ |
| 218 | if ( i>4 && strcmp((zEncoded+i)-5, ".lock")==0 ) |
| 219 | memset((zEncoded+w)-5, REFREPLACEMENT, 5); |
| 220 | } |
| 221 | printf("%s", zEncoded); |
| 222 | free(zEncoded); |
| 223 | } |
| 224 | |
| 225 | #define BLOBMARK(rid) ((rid) * 2) |
| 226 | #define COMMITMARK(rid) ((rid) * 2 + 1) |
| 227 | |
| 228 | /* |
| @@ -547,26 +605,22 @@ | |
| 605 | const char *zSecondsSince1970 = db_column_text(&q, 0); |
| 606 | int ckinId = db_column_int(&q, 1); |
| 607 | const char *zComment = db_column_text(&q, 2); |
| 608 | const char *zUser = db_column_text(&q, 3); |
| 609 | const char *zBranch = db_column_text(&q, 4); |
| 610 | char *zMark; |
| 611 | |
| 612 | bag_insert(&vers, ckinId); |
| 613 | db_bind_int(&q2, ":rid", ckinId); |
| 614 | db_step(&q2); |
| 615 | db_reset(&q2); |
| 616 | if( zBranch==0 ) zBranch = "trunk"; |
| 617 | zMark = mark_name_from_rid(ckinId, &unused_mark); |
| 618 | printf("commit refs/heads/"); |
| 619 | print_ref(zBranch); |
| 620 | printf("\nmark %s\n", zMark); |
| 621 | free(zMark); |
| 622 | printf("committer"); |
| 623 | print_person(zUser); |
| 624 | printf(" %s +0000\n", zSecondsSince1970); |
| 625 | if( zComment==0 ) zComment = "null comment"; |
| 626 | printf("data %d\n%s\n", (int)strlen(zComment), zComment); |
| @@ -637,30 +691,24 @@ | |
| 691 | " FROM tagxref JOIN tag USING(tagid)" |
| 692 | " WHERE tagtype=1 AND tagname GLOB 'sym-*'" |
| 693 | ); |
| 694 | while( db_step(&q)==SQLITE_ROW ){ |
| 695 | const char *zTagname = db_column_text(&q, 0); |
| 696 | int rid = db_column_int(&q, 1); |
| 697 | char *zMark = mark_name_from_rid(rid, &unused_mark); |
| 698 | const char *zSecSince1970 = db_column_text(&q, 2); |
| 699 | const char *zUser = db_column_text(&q, 3); |
| 700 | if( rid==0 || !bag_find(&vers, rid) ) continue; |
| 701 | zTagname += 4; |
| 702 | printf("tag "); |
| 703 | print_ref(zTagname); |
| 704 | printf("\nfrom %s\n", zMark); |
| 705 | free(zMark); |
| 706 | printf("tagger"); |
| 707 | print_person(zUser); |
| 708 | printf(" %s +0000\n", zSecSince1970); |
| 709 | printf("data 0\n"); |
| 710 | } |
| 711 | db_finalize(&q); |
| 712 | |
| 713 | if( markfile_out!=0 ){ |
| 714 | FILE *f; |
| 715 |