Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Add the BACKLINK table and code to populate it. NB: Run "rebuild" when updating to this or later versions. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
f2181f5e45b62da9c11fc6258f555593 |
| User & Date: | drh 2010-03-15 14:46:20.000 |
Context
|
2010-03-15
| ||
| 16:16 | Show check-ins that mention a ticket in the ticket timeline. check-in: 611b3b206b user: drh tags: trunk | |
| 14:46 | Add the BACKLINK table and code to populate it. NB: Run "rebuild" when updating to this or later versions. check-in: f2181f5e45 user: drh tags: trunk | |
|
2010-03-14
| ||
| 20:56 | Add an exception to the GPLv2 license to allow Fossil to be linked against the OpenSSL library. Ticket [930a168303]. check-in: 01c2f049b4 user: drh tags: trunk | |
Changes
Changes to src/manifest.c.
| ︙ | ︙ | |||
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 |
if( g.xlinkClusterOnly && m.type!=CFTYPE_CLUSTER ){
manifest_clear(&m);
return 0;
}
db_begin_transaction();
if( m.type==CFTYPE_MANIFEST ){
if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){
for(i=0; i<m.nParent; i++){
int pid = uuid_to_rid(m.azParent[i], 1);
db_multi_exec("INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime)"
"VALUES(%d, %d, %d, %.17g)", pid, rid, i==0, m.rDate);
if( i==0 ){
add_mlink(pid, 0, rid, &m);
parentid = pid;
| > | 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 |
if( g.xlinkClusterOnly && m.type!=CFTYPE_CLUSTER ){
manifest_clear(&m);
return 0;
}
db_begin_transaction();
if( m.type==CFTYPE_MANIFEST ){
if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){
char *zCom;
for(i=0; i<m.nParent; i++){
int pid = uuid_to_rid(m.azParent[i], 1);
db_multi_exec("INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime)"
"VALUES(%d, %d, %d, %.17g)", pid, rid, i==0, m.rDate);
if( i==0 ){
add_mlink(pid, 0, rid, &m);
parentid = pid;
|
| ︙ | ︙ | |||
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 |
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));",
TAG_DATE, rid, m.rDate,
rid, m.zUser, m.zComment,
TAG_BGCOLOR, rid,
TAG_USER, rid,
TAG_COMMENT, rid
);
}
}
if( m.type==CFTYPE_CLUSTER ){
tag_insert("cluster", 1, 0, rid, m.rDate, rid);
for(i=0; i<m.nCChild; i++){
int mid;
mid = uuid_to_rid(m.azCChild[i], 1);
| > > > > | 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 |
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));",
TAG_DATE, rid, m.rDate,
rid, m.zUser, m.zComment,
TAG_BGCOLOR, rid,
TAG_USER, rid,
TAG_COMMENT, rid
);
zCom = db_text(0, "SELECT coalesce(ecomment, comment) FROM event"
" WHERE rowid=last_insert_rowid()");
wiki_extract_links(zCom, rid, 0, m.rDate, 1, WIKI_INLINE);
free(zCom);
}
}
if( m.type==CFTYPE_CLUSTER ){
tag_insert("cluster", 1, 0, rid, m.rDate, rid);
for(i=0; i<m.nCChild; i++){
int mid;
mid = uuid_to_rid(m.azCChild[i], 1);
|
| ︙ | ︙ |
Changes to src/schema.c.
| ︙ | ︙ | |||
306 307 308 309 310 311 312 313 314 315 316 317 318 319 | @ origid INTEGER REFERENCES blob, -- check-in holding propagated tag @ value TEXT, -- Value of the tag. Might be NULL. @ mtime TIMESTAMP, -- Time of addition or removal @ rid INTEGER REFERENCE blob, -- Artifact tag is applied to @ UNIQUE(rid, tagid) @ ); @ CREATE INDEX tagxref_i1 ON tagxref(tagid, mtime); @ @ -- Template for the TICKET table @ -- @ -- NB: when changing the schema of the TICKET table here, also make the @ -- same change in tktsetup.c. @ -- @ CREATE TABLE ticket( | > > > > > > > > > > > > > > | 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | @ origid INTEGER REFERENCES blob, -- check-in holding propagated tag @ value TEXT, -- Value of the tag. Might be NULL. @ mtime TIMESTAMP, -- Time of addition or removal @ rid INTEGER REFERENCE blob, -- Artifact tag is applied to @ UNIQUE(rid, tagid) @ ); @ CREATE INDEX tagxref_i1 ON tagxref(tagid, mtime); @ @ -- When a hyperlink occurs from one artifact to another (for example @ -- when a check-in comment refers to a ticket) an entry is made in @ -- the following table for that hyperlink. This table is used to @ -- facilitate the display of "back links". @ -- @ CREATE TABLE backlink( @ target TEXT, -- Where the hyperlink points to @ srctype INT, -- 0: check-in 1: ticket 2: wiki @ srcid INT, -- rid for checkin or wiki. tkt_id for ticket. @ mtime TIMESTAMP, -- time that the hyperlink was added @ UNIQUE(target, srctype, srcid) @ ); @ CREATE INDEX backlink_src ON backlink(srcid, srctype); @ @ -- Template for the TICKET table @ -- @ -- NB: when changing the schema of the TICKET table here, also make the @ -- same change in tktsetup.c. @ -- @ CREATE TABLE ticket( |
| ︙ | ︙ |
Changes to src/tag.c.
| ︙ | ︙ | |||
198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
case TAG_USER: {
zCol = "euser";
break;
}
}
if( zCol ){
db_multi_exec("UPDATE event SET %s=%Q WHERE objid=%d", zCol, zValue, rid);
}
if( tagid==TAG_DATE ){
db_multi_exec("UPDATE event SET mtime=julianday(%Q) WHERE objid=%d",
zValue, rid);
}
if( tagtype==0 || tagtype==2 ){
tag_propagate(rid, tagid, tagtype, rid, zValue, mtime);
| > > > > > | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
case TAG_USER: {
zCol = "euser";
break;
}
}
if( zCol ){
db_multi_exec("UPDATE event SET %s=%Q WHERE objid=%d", zCol, zValue, rid);
if( tagid==TAG_COMMENT ){
char *zCopy = mprintf("%s", zValue);
wiki_extract_links(zCopy, rid, 0, mtime, 1, WIKI_INLINE);
free(zCopy);
}
}
if( tagid==TAG_DATE ){
db_multi_exec("UPDATE event SET mtime=julianday(%Q) WHERE objid=%d",
zValue, rid);
}
if( tagtype==0 || tagtype==2 ){
tag_propagate(rid, tagid, tagtype, rid, zValue, mtime);
|
| ︙ | ︙ |
Changes to src/wikiformat.c.
| ︙ | ︙ | |||
618 619 620 621 622 623 624 | /* ** Parse only Wiki links, return everything else as TOKEN_RAW. ** ** z points to the start of a token. Return the number of ** characters in that token. Write the token type into *pTokenType. */ | < | 618 619 620 621 622 623 624 625 626 627 628 629 630 631 |
/*
** Parse only Wiki links, return everything else as TOKEN_RAW.
**
** z points to the start of a token. Return the number of
** characters in that token. Write the token type into *pTokenType.
*/
static int nextRawToken(const char *z, Renderer *p, int *pTokenType){
int n;
if( z[0]=='[' && (n = linkLength(z))>0 ){
*pTokenType = TOKEN_LINK;
return n;
}
*pTokenType = TOKEN_RAW;
|
| ︙ | ︙ | |||
776 777 778 779 780 781 782 |
** output its end tag if it is not a </div> tag.
*/
static void popStack(Renderer *p){
if( p->nStack ){
int iCode;
p->nStack--;
iCode = p->aStack[p->nStack].iCode;
| | | 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 |
** output its end tag if it is not a </div> tag.
*/
static void popStack(Renderer *p){
if( p->nStack ){
int iCode;
p->nStack--;
iCode = p->aStack[p->nStack].iCode;
if( iCode!=MARKUP_DIV && p->pOut ){
blob_appendf(p->pOut, "</%s>", aMarkup[iCode].zName);
}
}
}
/*
** Push a new markup value onto the stack. Enlarge the stack
|
| ︙ | ︙ | |||
1445 1446 1447 1448 1449 1450 1451 |
iStart = i+6;
for(i=iStart; z[i] && (z[i]!='<' || strncmp(&z[i],"</title>",8)!=0); i++){}
if( z[i]!='<' ) return 0;
blob_init(pTitle, &z[iStart], i-iStart);
blob_init(pTail, &z[i+8], -1);
return 1;
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 |
iStart = i+6;
for(i=iStart; z[i] && (z[i]!='<' || strncmp(&z[i],"</title>",8)!=0); i++){}
if( z[i]!='<' ) return 0;
blob_init(pTitle, &z[iStart], i-iStart);
blob_init(pTail, &z[i+8], -1);
return 1;
}
/*
** Parse text looking for wiki hyperlinks in one of the formats:
**
** [target]
** [target|...]
**
** Where "target" can be either an artifact ID prefix or a wiki page
** name. For each such hyperlink found, add an entry to the
** backlink table.
*/
void wiki_extract_links(
char *z, /* The wiki text from which to extract links */
int srcid, /* srcid field for new BACKLINK table entries */
int srctype, /* srctype field for new BACKLINK table entries */
double mtime, /* mtime field for new BACKLINK table entries */
int replaceFlag, /* True first delete prior BACKLINK entries */
int flags /* wiki parsing flags */
){
Renderer renderer;
int tokenType;
ParsedMarkup markup;
int n;
int inlineOnly;
int wikiUseHtml = 0;
memset(&renderer, 0, sizeof(renderer));
renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH;
if( flags & WIKI_NOBLOCK ){
renderer.state |= INLINE_MARKUP_ONLY;
}
if( db_get_int("wiki-use-html", 0) ){
renderer.state |= WIKI_USE_HTML;
wikiUseHtml = 1;
}
inlineOnly = (renderer.state & INLINE_MARKUP_ONLY)!=0;
if( replaceFlag ){
db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid=%d",
srctype, srcid);
}
while( z[0] ){
if( wikiUseHtml ){
n = nextRawToken(z, &renderer, &tokenType);
}else{
n = nextWikiToken(z, &renderer, &tokenType);
}
switch( tokenType ){
case TOKEN_LINK: {
char *zTarget;
int i, c;
char zLink[42];
zTarget = &z[1];
for(i=0; zTarget[i] && zTarget[i]!='|' && zTarget[i]!=']'; i++){}
while(i>1 && zTarget[i-1]==' '){ i--; }
c = zTarget[i];
zTarget[i] = 0;
if( is_valid_uuid(zTarget) ){
memcpy(zLink, zTarget, i+1);
canonical16(zLink, i);
db_multi_exec(
"REPLACE INTO backlink(target,srctype,srcid,mtime)"
"VALUES(%Q,%d,%d,%g)", zLink, srctype, srcid, mtime
);
}
zTarget[i] = c;
break;
}
case TOKEN_MARKUP: {
const char *zId;
int iDiv;
parseMarkup(&markup, z);
/* Markup of the form </div id=ID> where there is a matching
** ID somewhere on the stack. Exit the verbatim if were are in
** it. Pop the stack up to the matching <div>. Discard the
** </div>
*/
if( markup.iCode==MARKUP_DIV && markup.endTag &&
(zId = markupId(&markup))!=0 &&
(iDiv = findTagWithId(&renderer, MARKUP_DIV, zId))>=0
){
if( renderer.inVerbatim ){
renderer.inVerbatim = 0;
renderer.state = renderer.preVerbState;
}
while( renderer.nStack>iDiv+1 ) popStack(&renderer);
if( renderer.aStack[iDiv].allowWiki ){
renderer.state |= ALLOW_WIKI;
}else{
renderer.state &= ~ALLOW_WIKI;
}
renderer.nStack--;
}else
/* If within <verbatim id=ID> ignore everything other than
** </verbatim id=ID> and the </dev id=ID2> above.
*/
if( renderer.inVerbatim ){
if( endVerbatim(&renderer, &markup) ){
renderer.inVerbatim = 0;
renderer.state = renderer.preVerbState;
}else{
n = 1;
}
}else
/* Render invalid markup literally. The markup appears in the
** final output as plain text.
*/
if( markup.iCode==MARKUP_INVALID ){
n = 1;
}else
/* If the markup is not font-change markup ignore it if the
** font-change-only flag is set.
*/
if( (markup.iType&MUTYPE_FONT)==0 &&
(renderer.state & FONT_MARKUP_ONLY)!=0 ){
/* Do nothing */
}else
if( markup.iCode==MARKUP_NOWIKI ){
if( markup.endTag ){
renderer.state |= ALLOW_WIKI;
}else{
renderer.state &= ~ALLOW_WIKI;
}
}else
/* Ignore block markup for in-line rendering.
*/
if( inlineOnly && (markup.iType&MUTYPE_INLINE)==0 ){
/* Do nothing */
}else
/* Generate end-tags */
if( markup.endTag ){
popStackToTag(&renderer, markup.iCode);
}else
/* Push <div> markup onto the stack together with the id=ID attribute.
*/
if( markup.iCode==MARKUP_DIV ){
pushStackWithId(&renderer, markup.iCode, markupId(&markup),
(renderer.state & ALLOW_WIKI)!=0);
}else
/* Enter <verbatim> processing. With verbatim enabled, all other
** markup other than the corresponding end-tag with the same ID is
** ignored.
*/
if( markup.iCode==MARKUP_VERBATIM ){
int vAttrIdx, vAttrDidAppend=0;
renderer.zVerbatimId = 0;
renderer.inVerbatim = 1;
renderer.preVerbState = renderer.state;
renderer.state &= ~ALLOW_WIKI;
for (vAttrIdx = 0; vAttrIdx < markup.nAttr; vAttrIdx++){
if( markup.aAttr[vAttrIdx].iACode == ATTR_ID ){
renderer.zVerbatimId = markup.aAttr[0].zValue;
}else if( markup.aAttr[vAttrIdx].iACode == ATTR_TYPE ){
vAttrDidAppend=1;
}
}
renderer.wantAutoParagraph = 0;
}
/* Restore the input text to its original configuration
*/
unparseMarkup(&markup);
break;
}
default: {
break;
}
}
z += n;
}
}
|