Fossil SCM

Cosmetic and style tweaks in test code.

stephan 2026-06-04 15:49 UTC attach-v2
Commit 4a0be8d60443d58c70a1206acc6a2358d97b5ce6b603fe12ee054f87ac939c93
1 file changed +65 -55
+65 -55
--- src/attach.c
+++ src/attach.c
@@ -22,32 +22,41 @@
2222
#include <assert.h>
2323
2424
/*
2525
** Given a presumedly legal attachment target name, this guesses the
2626
** target type and returns one of CFTYPE_FORUM, CFTYPE_WIKI,
27
-** CFTYPE_TICKET, or CFTYPE_EVENT. Returns 0 if it cannot
28
-** distinguish the target type.
29
-**
30
-** If bFull is true then it requires zTarget to be an exact matches
31
-** for wiki, tech-note, and ticket IDs. If bFull is false then
32
-** tech-notes and tickets will perform a prefix match, but it is up to
33
-** the caller to provide enough of a prefix to rule out a
34
-** collision[^1]. Forum posts are a special case and ignore the bFull
35
-** flag. When called repeatedly, this routine can run a bit faster and
36
-** more efficiently if bFull is true, but some historical use cases
37
-** call for prefix matches.
38
-**
39
-** In the case of CFTYPE_FORUM, it is up to the caller to ensure that,
40
-** if needed, they resolve zTarget using forumpost_head_rid2() so that
41
-** they get the RID of the earliest version of the post, as that is
42
-** the only one which attachments should target.
43
-**
44
-** [^1]: Historically (as of 2026-06) attachment target lookups have
45
-** used GLOB prefix matching but taken no measures to ensure that the
46
-** prefix is unambiguous. Ergo we don't here, either. It is assumed
47
-** that the caller passes enough of a prefix to be unambiguous and
48
-** that's worked out fine so far.
27
+** CFTYPE_TICKET, or CFTYPE_EVENT. Returns 0 if it cannot distinguish
28
+** the target type.
29
+**
30
+** zTarget is an attachment target name: wiki page name, tech-note ID,
31
+** ticket ID, or forumpost hash.
32
+**
33
+** If bFull is true then it requires zTarget to be a full ID for
34
+** tech-notes and tickets, otherwise such IDs may be prefixes. If
35
+** bFull is false then tech-notes and tickets will perform a prefix
36
+** match, but it is up to the caller to provide enough of a prefix to
37
+** rule out a collision[^1]. When called repeatedly, this routine can
38
+** run a bit faster and more efficiently if bFull is true, but some
39
+** historical use cases call for prefix matches.
40
+**
41
+** Wiki page names always require an exact match.
42
+**
43
+** Forum posts are a special case:
44
+**
45
+** - The ignore the bFull flag. That is, they will do prefix matches
46
+** but will not match an ambiguous prefix.
47
+**
48
+** - It is up to the caller to, if needed, resolve zTarget using
49
+** forumpost_head_rid2() to resolve the RID of the earliest version
50
+** of the post, as that is the only one which attachments should
51
+** target.
52
+**
53
+** [^1]: Historically (from the perspective of 2026-06) attachment
54
+** target lookups have used GLOB prefix matching but have taken no
55
+** measures to ensure that the prefix is unambiguous. Ergo we don't
56
+** here, either. It is assumed that the caller passes enough of a
57
+** prefix to be unambiguous and that's worked out fine so far.
4958
*/
5059
int attachment_target_type(const char *zTarget, int bFull){
5160
if( !zTarget || !zTarget[0] || strlen(zTarget)>64/*vs. abuse*/ ){
5261
return 0;
5362
}
@@ -95,14 +104,14 @@
95104
}
96105
}
97106
98107
/*
99108
** Given an attachment target name, returns the target's blob.rid.
100
-** zTarget must be a full wiki page name, tech-note ID, ticket ID, or
101
-** forum post hash. Returns 0 if no match is found.
109
+** zTarget and bFull work as described for attachment_target_type().
102110
**
103
-** bFull is interpreted as per attachment_target_type().
111
+** For forum posts, this always returns the RID of the first version
112
+** of the post, as attachments should always target that instance.
104113
*/
105114
int attachment_target_rid(const char *zTarget, int bFull){
106115
int rid = 0;
107116
const int eType = attachment_target_type(zTarget, bFull);
108117
switch(eType){
@@ -1660,67 +1669,68 @@
16601669
const char *zTarget = g.argv[i];
16611670
const int rid = attachment_target_rid(zTarget, 0);
16621671
const int type = attachment_target_type(zTarget, 0);
16631672
const char *zType = "<invalid>";
16641673
switch(type){
1665
- case CFTYPE_EVENT: zType = "e"; break;
1666
- case CFTYPE_FORUM: zType = "f"; break;
1667
- case CFTYPE_TICKET: zType = "t"; break;
1668
- case CFTYPE_WIKI: zType = "w"; break;
1674
+ case CFTYPE_EVENT: zType = "technote"; break;
1675
+ case CFTYPE_FORUM: zType = "forumpost"; break;
1676
+ case CFTYPE_TICKET: zType = "ticket"; break;
1677
+ case CFTYPE_WIKI: zType = "wiki"; break;
16691678
}
1670
- fossil_print("%-20s = %s %d %z\n",
1679
+ fossil_print("%-20s = %-9s #%d %z\n",
16711680
zTarget, zType, rid,
16721681
rid>0 ? rid_to_uuid(rid) : 0);
16731682
}
16741683
}
16751684
16761685
16771686
/*
16781687
** COMMAND: test-attachments-to-json
16791688
**
1680
-** Usage: %fossil test-attachments-to-json TARGET_ID
1689
+** Usage: %fossil test-attachments-to-json TARGET_ID...
16811690
**
16821691
** Options:
16831692
** --old List all versions of attachments. Default is to
16841693
** list only the latest.
16851694
** --full Require a full target ID, not a prefix.
16861695
**
1687
-** Emits a JSON array of attachments for the given attachment target.
1688
-** The given ID must be a wiki page name, ticket hash, tech-note hash,
1689
-** or forum post hash. By default it accepts prefixes but does not
1690
-** detection of ambiguity or cross-type prefix collisions so may emit
1691
-** curious results if given short/colliding IDs.
1696
+** Emits a JSON array of attachments for the given attachment targets.
1697
+** The given IDs must be wiki page names, ticket hashes, tech-note
1698
+** hashes, or forum post hashes. By default it accepts hash prefixes
1699
+** but does no detection of ambiguity or cross-type prefix collisions
1700
+** so may emit curious results if given short, colliding IDs.
16921701
*/
16931702
void test_attachments_to_json_cmd(void){
1694
- Manifest *pManifest;
1695
- Blob b = BLOB_INITIALIZER;
1696
- int bLatestOnly = find_option("old",0,0)==0;
1697
- int emptyPolicy = 1;
1698
- int rid, i;
1699
- int bFullId = find_option("full",0,0)!=0;
1703
+ const int emptyPolicy = 1;
1704
+ const int bLatestOnly = find_option("old",0,0)==0;
1705
+ const int bFullId = find_option("full",0,0)!=0;
1706
+ int i;
1707
+
17001708
verify_all_options();
17011709
db_find_and_open_repository(0, 0);
17021710
if( g.argc<3 ){
17031711
usage("test-attachments-to-json TARGET_ID");
17041712
return;
17051713
}
17061714
for( i = 2; i < g.argc; ++i ){
17071715
const char *zTarget = g.argv[i];
1708
- rid = attachment_target_rid(zTarget, bFullId);
1716
+ const int rid = attachment_target_rid(zTarget, bFullId);
17091717
if( 0==rid ){
17101718
fossil_print("** cannot resolve %s\n", zTarget);
1711
- continue;
1712
- }
1713
- pManifest = manifest_get(rid, CFTYPE_ANY, NULL);
1714
- attachments_to_json(pManifest, &b, bLatestOnly, emptyPolicy);
1715
- fossil_print("Attachments for %s: ", zTarget);
1716
- if( b.nUsed ){
1717
- char *zPretty = db_text(0,"SELECT json_pretty(%B)", &b);
1718
- fossil_print("%s\n", zPretty);
1719
- fossil_free(zPretty);
17201719
}else{
1721
- fossil_print("none\n");
1720
+ Blob b = BLOB_INITIALIZER;
1721
+ Manifest *pManifest = manifest_get(rid, CFTYPE_ANY, NULL);
1722
+ assert( pManifest );
1723
+ attachments_to_json(pManifest, &b, bLatestOnly, emptyPolicy);
1724
+ fossil_print("Attachments for %s: ", zTarget);
1725
+ if( b.nUsed ){
1726
+ char *zPretty = db_text(0,"SELECT json_pretty(%B)", &b);
1727
+ fossil_print("%s\n", zPretty);
1728
+ fossil_free(zPretty);
1729
+ }else{
1730
+ fossil_print("none\n");
1731
+ }
1732
+ blob_reset(&b);
1733
+ manifest_destroy(pManifest);
17221734
}
1723
- blob_reset(&b);
1724
- manifest_destroy(pManifest);
17251735
}
17261736
}
17271737
--- src/attach.c
+++ src/attach.c
@@ -22,32 +22,41 @@
22 #include <assert.h>
23
24 /*
25 ** Given a presumedly legal attachment target name, this guesses the
26 ** target type and returns one of CFTYPE_FORUM, CFTYPE_WIKI,
27 ** CFTYPE_TICKET, or CFTYPE_EVENT. Returns 0 if it cannot
28 ** distinguish the target type.
29 **
30 ** If bFull is true then it requires zTarget to be an exact matches
31 ** for wiki, tech-note, and ticket IDs. If bFull is false then
32 ** tech-notes and tickets will perform a prefix match, but it is up to
33 ** the caller to provide enough of a prefix to rule out a
34 ** collision[^1]. Forum posts are a special case and ignore the bFull
35 ** flag. When called repeatedly, this routine can run a bit faster and
36 ** more efficiently if bFull is true, but some historical use cases
37 ** call for prefix matches.
38 **
39 ** In the case of CFTYPE_FORUM, it is up to the caller to ensure that,
40 ** if needed, they resolve zTarget using forumpost_head_rid2() so that
41 ** they get the RID of the earliest version of the post, as that is
42 ** the only one which attachments should target.
43 **
44 ** [^1]: Historically (as of 2026-06) attachment target lookups have
45 ** used GLOB prefix matching but taken no measures to ensure that the
46 ** prefix is unambiguous. Ergo we don't here, either. It is assumed
47 ** that the caller passes enough of a prefix to be unambiguous and
48 ** that's worked out fine so far.
 
 
 
 
 
 
 
 
 
49 */
50 int attachment_target_type(const char *zTarget, int bFull){
51 if( !zTarget || !zTarget[0] || strlen(zTarget)>64/*vs. abuse*/ ){
52 return 0;
53 }
@@ -95,14 +104,14 @@
95 }
96 }
97
98 /*
99 ** Given an attachment target name, returns the target's blob.rid.
100 ** zTarget must be a full wiki page name, tech-note ID, ticket ID, or
101 ** forum post hash. Returns 0 if no match is found.
102 **
103 ** bFull is interpreted as per attachment_target_type().
 
104 */
105 int attachment_target_rid(const char *zTarget, int bFull){
106 int rid = 0;
107 const int eType = attachment_target_type(zTarget, bFull);
108 switch(eType){
@@ -1660,67 +1669,68 @@
1660 const char *zTarget = g.argv[i];
1661 const int rid = attachment_target_rid(zTarget, 0);
1662 const int type = attachment_target_type(zTarget, 0);
1663 const char *zType = "<invalid>";
1664 switch(type){
1665 case CFTYPE_EVENT: zType = "e"; break;
1666 case CFTYPE_FORUM: zType = "f"; break;
1667 case CFTYPE_TICKET: zType = "t"; break;
1668 case CFTYPE_WIKI: zType = "w"; break;
1669 }
1670 fossil_print("%-20s = %s %d %z\n",
1671 zTarget, zType, rid,
1672 rid>0 ? rid_to_uuid(rid) : 0);
1673 }
1674 }
1675
1676
1677 /*
1678 ** COMMAND: test-attachments-to-json
1679 **
1680 ** Usage: %fossil test-attachments-to-json TARGET_ID
1681 **
1682 ** Options:
1683 ** --old List all versions of attachments. Default is to
1684 ** list only the latest.
1685 ** --full Require a full target ID, not a prefix.
1686 **
1687 ** Emits a JSON array of attachments for the given attachment target.
1688 ** The given ID must be a wiki page name, ticket hash, tech-note hash,
1689 ** or forum post hash. By default it accepts prefixes but does not
1690 ** detection of ambiguity or cross-type prefix collisions so may emit
1691 ** curious results if given short/colliding IDs.
1692 */
1693 void test_attachments_to_json_cmd(void){
1694 Manifest *pManifest;
1695 Blob b = BLOB_INITIALIZER;
1696 int bLatestOnly = find_option("old",0,0)==0;
1697 int emptyPolicy = 1;
1698 int rid, i;
1699 int bFullId = find_option("full",0,0)!=0;
1700 verify_all_options();
1701 db_find_and_open_repository(0, 0);
1702 if( g.argc<3 ){
1703 usage("test-attachments-to-json TARGET_ID");
1704 return;
1705 }
1706 for( i = 2; i < g.argc; ++i ){
1707 const char *zTarget = g.argv[i];
1708 rid = attachment_target_rid(zTarget, bFullId);
1709 if( 0==rid ){
1710 fossil_print("** cannot resolve %s\n", zTarget);
1711 continue;
1712 }
1713 pManifest = manifest_get(rid, CFTYPE_ANY, NULL);
1714 attachments_to_json(pManifest, &b, bLatestOnly, emptyPolicy);
1715 fossil_print("Attachments for %s: ", zTarget);
1716 if( b.nUsed ){
1717 char *zPretty = db_text(0,"SELECT json_pretty(%B)", &b);
1718 fossil_print("%s\n", zPretty);
1719 fossil_free(zPretty);
1720 }else{
1721 fossil_print("none\n");
 
 
 
 
 
 
 
 
 
 
 
 
 
1722 }
1723 blob_reset(&b);
1724 manifest_destroy(pManifest);
1725 }
1726 }
1727
--- src/attach.c
+++ src/attach.c
@@ -22,32 +22,41 @@
22 #include <assert.h>
23
24 /*
25 ** Given a presumedly legal attachment target name, this guesses the
26 ** target type and returns one of CFTYPE_FORUM, CFTYPE_WIKI,
27 ** CFTYPE_TICKET, or CFTYPE_EVENT. Returns 0 if it cannot distinguish
28 ** the target type.
29 **
30 ** zTarget is an attachment target name: wiki page name, tech-note ID,
31 ** ticket ID, or forumpost hash.
32 **
33 ** If bFull is true then it requires zTarget to be a full ID for
34 ** tech-notes and tickets, otherwise such IDs may be prefixes. If
35 ** bFull is false then tech-notes and tickets will perform a prefix
36 ** match, but it is up to the caller to provide enough of a prefix to
37 ** rule out a collision[^1]. When called repeatedly, this routine can
38 ** run a bit faster and more efficiently if bFull is true, but some
39 ** historical use cases call for prefix matches.
40 **
41 ** Wiki page names always require an exact match.
42 **
43 ** Forum posts are a special case:
44 **
45 ** - The ignore the bFull flag. That is, they will do prefix matches
46 ** but will not match an ambiguous prefix.
47 **
48 ** - It is up to the caller to, if needed, resolve zTarget using
49 ** forumpost_head_rid2() to resolve the RID of the earliest version
50 ** of the post, as that is the only one which attachments should
51 ** target.
52 **
53 ** [^1]: Historically (from the perspective of 2026-06) attachment
54 ** target lookups have used GLOB prefix matching but have taken no
55 ** measures to ensure that the prefix is unambiguous. Ergo we don't
56 ** here, either. It is assumed that the caller passes enough of a
57 ** prefix to be unambiguous and that's worked out fine so far.
58 */
59 int attachment_target_type(const char *zTarget, int bFull){
60 if( !zTarget || !zTarget[0] || strlen(zTarget)>64/*vs. abuse*/ ){
61 return 0;
62 }
@@ -95,14 +104,14 @@
104 }
105 }
106
107 /*
108 ** Given an attachment target name, returns the target's blob.rid.
109 ** zTarget and bFull work as described for attachment_target_type().
 
110 **
111 ** For forum posts, this always returns the RID of the first version
112 ** of the post, as attachments should always target that instance.
113 */
114 int attachment_target_rid(const char *zTarget, int bFull){
115 int rid = 0;
116 const int eType = attachment_target_type(zTarget, bFull);
117 switch(eType){
@@ -1660,67 +1669,68 @@
1669 const char *zTarget = g.argv[i];
1670 const int rid = attachment_target_rid(zTarget, 0);
1671 const int type = attachment_target_type(zTarget, 0);
1672 const char *zType = "<invalid>";
1673 switch(type){
1674 case CFTYPE_EVENT: zType = "technote"; break;
1675 case CFTYPE_FORUM: zType = "forumpost"; break;
1676 case CFTYPE_TICKET: zType = "ticket"; break;
1677 case CFTYPE_WIKI: zType = "wiki"; break;
1678 }
1679 fossil_print("%-20s = %-9s #%d %z\n",
1680 zTarget, zType, rid,
1681 rid>0 ? rid_to_uuid(rid) : 0);
1682 }
1683 }
1684
1685
1686 /*
1687 ** COMMAND: test-attachments-to-json
1688 **
1689 ** Usage: %fossil test-attachments-to-json TARGET_ID...
1690 **
1691 ** Options:
1692 ** --old List all versions of attachments. Default is to
1693 ** list only the latest.
1694 ** --full Require a full target ID, not a prefix.
1695 **
1696 ** Emits a JSON array of attachments for the given attachment targets.
1697 ** The given IDs must be wiki page names, ticket hashes, tech-note
1698 ** hashes, or forum post hashes. By default it accepts hash prefixes
1699 ** but does no detection of ambiguity or cross-type prefix collisions
1700 ** so may emit curious results if given short, colliding IDs.
1701 */
1702 void test_attachments_to_json_cmd(void){
1703 const int emptyPolicy = 1;
1704 const int bLatestOnly = find_option("old",0,0)==0;
1705 const int bFullId = find_option("full",0,0)!=0;
1706 int i;
1707
 
1708 verify_all_options();
1709 db_find_and_open_repository(0, 0);
1710 if( g.argc<3 ){
1711 usage("test-attachments-to-json TARGET_ID");
1712 return;
1713 }
1714 for( i = 2; i < g.argc; ++i ){
1715 const char *zTarget = g.argv[i];
1716 const int rid = attachment_target_rid(zTarget, bFullId);
1717 if( 0==rid ){
1718 fossil_print("** cannot resolve %s\n", zTarget);
 
 
 
 
 
 
 
 
 
1719 }else{
1720 Blob b = BLOB_INITIALIZER;
1721 Manifest *pManifest = manifest_get(rid, CFTYPE_ANY, NULL);
1722 assert( pManifest );
1723 attachments_to_json(pManifest, &b, bLatestOnly, emptyPolicy);
1724 fossil_print("Attachments for %s: ", zTarget);
1725 if( b.nUsed ){
1726 char *zPretty = db_text(0,"SELECT json_pretty(%B)", &b);
1727 fossil_print("%s\n", zPretty);
1728 fossil_free(zPretty);
1729 }else{
1730 fossil_print("none\n");
1731 }
1732 blob_reset(&b);
1733 manifest_destroy(pManifest);
1734 }
 
 
1735 }
1736 }
1737

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button