Check-in [f2181f5e45]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
SHA1 Hash:f2181f5e45b62da9c11fc6258f555593ef7b2b6c
Date: 2010-03-15 14:46:20
User: drh
Comment:Add the BACKLINK table and code to populate it. NB: Run "rebuild" when updating to this or later versions.
Tags And Properties
Changes

Changes to src/manifest.c

Old (fbdeafd71ccbf7f9) New (04b8bfbf43e39d8c)
1 /* 1 /*
2 ** Copyright (c) 2007 D. Richard Hipp 2 ** Copyright (c) 2007 D. Richard Hipp
3 ** 3 **
4 ** This program is free software; you can redistribute it and/or 4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU General Public 5 ** modify it under the terms of the GNU General Public
1026 hidden lines
1032 return 0; 1032 return 0;
1033 } 1033 }
1034 db_begin_transaction(); 1034 db_begin_transaction();
1035 if( m.type==CFTYPE_MANIFEST ){ 1035 if( m.type==CFTYPE_MANIFEST ){
1036 if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){ 1036 if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){
> 1037 char *zCom;
1037 for(i=0; i<m.nParent; i++){ 1038 for(i=0; i<m.nParent; i++){
1038 int pid = uuid_to_rid(m.azParent[i], 1); 1039 int pid = uuid_to_rid(m.azParent[i], 1);
1039 db_multi_exec("INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime)" 1040 db_multi_exec("INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime)"
1040 "VALUES(%d, %d, %d, %.17g)", pid, rid, i==0, m.rDate); 1041 "VALUES(%d, %d, %d, %.17g)", pid, rid, i==0, m.rDate);
1041 if( i==0 ){ 1042 if( i==0 ){
23 hidden lines
1065 rid, m.zUser, m.zComment, 1066 rid, m.zUser, m.zComment,
1066 TAG_BGCOLOR, rid, 1067 TAG_BGCOLOR, rid,
1067 TAG_USER, rid, 1068 TAG_USER, rid,
1068 TAG_COMMENT, rid 1069 TAG_COMMENT, rid
1069 ); 1070 );
> 1071 zCom = db_text(0, "SELECT coalesce(ecomment, comment) FROM event"
> 1072 " WHERE rowid=last_insert_rowid()");
> 1073 wiki_extract_links(zCom, rid, 0, m.rDate, 1, WIKI_INLINE);
> 1074 free(zCom);
1070 } 1075 }
1071 } 1076 }
1072 if( m.type==CFTYPE_CLUSTER ){ 1077 if( m.type==CFTYPE_CLUSTER ){
1073 tag_insert("cluster", 1, 0, rid, m.rDate, rid); 1078 tag_insert("cluster", 1, 0, rid, m.rDate, rid);
1074 for(i=0; i<m.nCChild; i++){ 1079 for(i=0; i<m.nCChild; i++){
74 hidden lines
1149 } 1154 }
1150 db_end_transaction(0); 1155 db_end_transaction(0);
1151 manifest_clear(&m); 1156 manifest_clear(&m);
1152 return 1; 1157 return 1;
1153 } 1158 }

Changes to src/schema.c

Old (4a9ad582dd3cedf6) New (51060ed8449af1e4)
1 /* 1 /*
2 ** Copyright (c) 2007 D. Richard Hipp 2 ** Copyright (c) 2007 D. Richard Hipp
3 ** 3 **
4 ** This program is free software; you can redistribute it and/or 4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU General Public 5 ** modify it under the terms of the GNU General Public
302 hidden lines
308 @ mtime TIMESTAMP, -- Time of addition or removal 308 @ mtime TIMESTAMP, -- Time of addition or removal
309 @ rid INTEGER REFERENCE blob, -- Artifact tag is applied to 309 @ rid INTEGER REFERENCE blob, -- Artifact tag is applied to
310 @ UNIQUE(rid, tagid) 310 @ UNIQUE(rid, tagid)
311 @ ); 311 @ );
312 @ CREATE INDEX tagxref_i1 ON tagxref(tagid, mtime); 312 @ CREATE INDEX tagxref_i1 ON tagxref(tagid, mtime);
> 313 @
> 314 @ -- When a hyperlink occurs from one artifact to another (for example
> 315 @ -- when a check-in comment refers to a ticket) an entry is made in
> 316 @ -- the following table for that hyperlink. This table is used to
> 317 @ -- facilitate the display of "back links".
> 318 @ --
> 319 @ CREATE TABLE backlink(
> 320 @ target TEXT, -- Where the hyperlink points to
> 321 @ srctype INT, -- 0: check-in 1: ticket 2: wiki
> 322 @ srcid INT, -- rid for checkin or wiki. tkt_id for ticket.
> 323 @ mtime TIMESTAMP, -- time that the hyperlink was added
> 324 @ UNIQUE(target, srctype, srcid)
> 325 @ );
> 326 @ CREATE INDEX backlink_src ON backlink(srcid, srctype);
313 @ 327 @
314 @ -- Template for the TICKET table 328 @ -- Template for the TICKET table
315 @ -- 329 @ --
316 @ -- NB: when changing the schema of the TICKET table here, also make the 330 @ -- NB: when changing the schema of the TICKET table here, also make the
317 @ -- same change in tktsetup.c. 331 @ -- same change in tktsetup.c.
97 hidden lines
415 @ merge INTEGER, -- Merged with this record 429 @ merge INTEGER, -- Merged with this record
416 @ UNIQUE(id, merge) 430 @ UNIQUE(id, merge)
417 @ ); 431 @ );
418 @ 432 @
419 ; 433 ;

Changes to src/tag.c

Old (53f57645df2929e4) New (8853a08ab87062e0)
1 /* 1 /*
2 ** Copyright (c) 2007 D. Richard Hipp 2 ** Copyright (c) 2007 D. Richard Hipp
3 ** 3 **
4 ** This program is free software; you can redistribute it and/or 4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU General Public 5 ** modify it under the terms of the GNU General Public
194 hidden lines
200 break; 200 break;
201 } 201 }
202 } 202 }
203 if( zCol ){ 203 if( zCol ){
204 db_multi_exec("UPDATE event SET %s=%Q WHERE objid=%d", zCol, zValue, rid); 204 db_multi_exec("UPDATE event SET %s=%Q WHERE objid=%d", zCol, zValue, rid);
> 205 if( tagid==TAG_COMMENT ){
> 206 char *zCopy = mprintf("%s", zValue);
> 207 wiki_extract_links(zCopy, rid, 0, mtime, 1, WIKI_INLINE);
> 208 free(zCopy);
> 209 }
205 } 210 }
206 if( tagid==TAG_DATE ){ 211 if( tagid==TAG_DATE ){
207 db_multi_exec("UPDATE event SET mtime=julianday(%Q) WHERE objid=%d", 212 db_multi_exec("UPDATE event SET mtime=julianday(%Q) WHERE objid=%d",
208 zValue, rid); 213 zValue, rid);
209 } 214 }
373 hidden lines
583 @ function xout(id){ 588 @ function xout(id){
584 @ } 589 @ }
585 @ </script> 590 @ </script>
586 style_footer(); 591 style_footer();
587 } 592 }

Changes to src/wikiformat.c

Old (79b7ccbe45fd5ca2) New (0a705ae0570c458a)
1 /* 1 /*
2 ** Copyright (c) 2007 D. Richard Hipp 2 ** Copyright (c) 2007 D. Richard Hipp
3 ** 3 **
4 ** This program is free software; you can redistribute it and/or 4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU General Public 5 ** modify it under the terms of the GNU General Public
614 hidden lines
620 ** Parse only Wiki links, return everything else as TOKEN_RAW. 620 ** Parse only Wiki links, return everything else as TOKEN_RAW.
621 ** 621 **
622 ** z points to the start of a token. Return the number of 622 ** z points to the start of a token. Return the number of
623 ** characters in that token. Write the token type into *pTokenType. 623 ** characters in that token. Write the token type into *pTokenType.
624 */ 624 */
625 <
626 static int nextRawToken(const char *z, Renderer *p, int *pTokenType){ 625 static int nextRawToken(const char *z, Renderer *p, int *pTokenType){
627 int n; 626 int n;
628 if( z[0]=='[' && (n = linkLength(z))>0 ){ 627 if( z[0]=='[' && (n = linkLength(z))>0 ){
629 *pTokenType = TOKEN_LINK; 628 *pTokenType = TOKEN_LINK;
630 return n; 629 return n;
147 hidden lines
778 static void popStack(Renderer *p){ 777 static void popStack(Renderer *p){
779 if( p->nStack ){ 778 if( p->nStack ){
780 int iCode; 779 int iCode;
781 p->nStack--; 780 p->nStack--;
782 iCode = p->aStack[p->nStack].iCode; 781 iCode = p->aStack[p->nStack].iCode;
783 if( iCode!=MARKUP_DIV ){ | 782 if( iCode!=MARKUP_DIV && p->pOut ){
784 blob_appendf(p->pOut, "</%s>", aMarkup[iCode].zName); 783 blob_appendf(p->pOut, "</%s>", aMarkup[iCode].zName);
785 } 784 }
786 } 785 }
787 } 786 }
788 787
657 hidden lines
1446 for(i=iStart; z[i] && (z[i]!='<' || strncmp(&z[i],"</title>",8)!=0); i++){} 1445 for(i=iStart; z[i] && (z[i]!='<' || strncmp(&z[i],"</title>",8)!=0); i++){}
1447 if( z[i]!='<' ) return 0; 1446 if( z[i]!='<' ) return 0;
1448 blob_init(pTitle, &z[iStart], i-iStart); 1447 blob_init(pTitle, &z[iStart], i-iStart);
1449 blob_init(pTail, &z[i+8], -1); 1448 blob_init(pTail, &z[i+8], -1);
1450 return 1; 1449 return 1;
> 1450 }
> 1451
> 1452 /*
> 1453 ** Parse text looking for wiki hyperlinks in one of the formats:
> 1454 **
> 1455 ** [target]
> 1456 ** [target|...]
> 1457 **
> 1458 ** Where "target" can be either an artifact ID prefix or a wiki page
> 1459 ** name. For each such hyperlink found, add an entry to the
> 1460 ** backlink table.
> 1461 */
> 1462 void wiki_extract_links(
> 1463 char *z, /* The wiki text from which to extract links */
> 1464 int srcid, /* srcid field for new BACKLINK table entries */
> 1465 int srctype, /* srctype field for new BACKLINK table entries */
> 1466 double mtime, /* mtime field for new BACKLINK table entries */
> 1467 int replaceFlag, /* True first delete prior BACKLINK entries */
> 1468 int flags /* wiki parsing flags */
> 1469 ){
> 1470 Renderer renderer;
> 1471 int tokenType;
> 1472 ParsedMarkup markup;
> 1473 int n;
> 1474 int inlineOnly;
> 1475 int wikiUseHtml = 0;
> 1476
> 1477 memset(&renderer, 0, sizeof(renderer));
> 1478 renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH;
> 1479 if( flags & WIKI_NOBLOCK ){
> 1480 renderer.state |= INLINE_MARKUP_ONLY;
> 1481 }
> 1482 if( db_get_int("wiki-use-html", 0) ){
> 1483 renderer.state |= WIKI_USE_HTML;
> 1484 wikiUseHtml = 1;
> 1485 }
> 1486 inlineOnly = (renderer.state & INLINE_MARKUP_ONLY)!=0;
> 1487 if( replaceFlag ){
> 1488 db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid=%d",
> 1489 srctype, srcid);
> 1490 }
> 1491
> 1492 while( z[0] ){
> 1493 if( wikiUseHtml ){
> 1494 n = nextRawToken(z, &renderer, &tokenType);
> 1495 }else{
> 1496 n = nextWikiToken(z, &renderer, &tokenType);
> 1497 }
> 1498 switch( tokenType ){
> 1499 case TOKEN_LINK: {
> 1500 char *zTarget;
> 1501 int i, c;
> 1502 char zLink[42];
> 1503
> 1504 zTarget = &z[1];
> 1505 for(i=0; zTarget[i] && zTarget[i]!='|' && zTarget[i]!=']'; i++){}
> 1506 while(i>1 && zTarget[i-1]==' '){ i--; }
> 1507 c = zTarget[i];
> 1508 zTarget[i] = 0;
> 1509 if( is_valid_uuid(zTarget) ){
> 1510 memcpy(zLink, zTarget, i+1);
> 1511 canonical16(zLink, i);
> 1512 db_multi_exec(
> 1513 "REPLACE INTO backlink(target,srctype,srcid,mtime)"
> 1514 "VALUES(%Q,%d,%d,%g)", zLink, srctype, srcid, mtime
> 1515 );
> 1516 }
> 1517 zTarget[i] = c;
> 1518 break;
> 1519 }
> 1520 case TOKEN_MARKUP: {
> 1521 const char *zId;
> 1522 int iDiv;
> 1523 parseMarkup(&markup, z);
> 1524
> 1525 /* Markup of the form </div id=ID> where there is a matching
> 1526 ** ID somewhere on the stack. Exit the verbatim if were are in
> 1527 ** it. Pop the stack up to the matching <div>. Discard the
> 1528 ** </div>
> 1529 */
> 1530 if( markup.iCode==MARKUP_DIV && markup.endTag &&
> 1531 (zId = markupId(&markup))!=0 &&
> 1532 (iDiv = findTagWithId(&renderer, MARKUP_DIV, zId))>=0
> 1533 ){
> 1534 if( renderer.inVerbatim ){
> 1535 renderer.inVerbatim = 0;
> 1536 renderer.state = renderer.preVerbState;
> 1537 }
> 1538 while( renderer.nStack>iDiv+1 ) popStack(&renderer);
> 1539 if( renderer.aStack[iDiv].allowWiki ){
> 1540 renderer.state |= ALLOW_WIKI;
> 1541 }else{
> 1542 renderer.state &= ~ALLOW_WIKI;
> 1543 }
> 1544 renderer.nStack--;
> 1545 }else
> 1546
> 1547 /* If within <verbatim id=ID> ignore everything other than
> 1548 ** </verbatim id=ID> and the </dev id=ID2> above.
> 1549 */
> 1550 if( renderer.inVerbatim ){
> 1551 if( endVerbatim(&renderer, &markup) ){
> 1552 renderer.inVerbatim = 0;
> 1553 renderer.state = renderer.preVerbState;
> 1554 }else{
> 1555 n = 1;
> 1556 }
> 1557 }else
> 1558
> 1559 /* Render invalid markup literally. The markup appears in the
> 1560 ** final output as plain text.
> 1561 */
> 1562 if( markup.iCode==MARKUP_INVALID ){
> 1563 n = 1;
> 1564 }else
> 1565
> 1566 /* If the markup is not font-change markup ignore it if the
> 1567 ** font-change-only flag is set.
> 1568 */
> 1569 if( (markup.iType&MUTYPE_FONT)==0 &&
> 1570 (renderer.state & FONT_MARKUP_ONLY)!=0 ){
> 1571 /* Do nothing */
> 1572 }else
> 1573
> 1574 if( markup.iCode==MARKUP_NOWIKI ){
> 1575 if( markup.endTag ){
> 1576 renderer.state |= ALLOW_WIKI;
> 1577 }else{
> 1578 renderer.state &= ~ALLOW_WIKI;
> 1579 }
> 1580 }else
> 1581
> 1582 /* Ignore block markup for in-line rendering.
> 1583 */
> 1584 if( inlineOnly && (markup.iType&MUTYPE_INLINE)==0 ){
> 1585 /* Do nothing */
> 1586 }else
> 1587
> 1588 /* Generate end-tags */
> 1589 if( markup.endTag ){
> 1590 popStackToTag(&renderer, markup.iCode);
> 1591 }else
> 1592
> 1593 /* Push <div> markup onto the stack together with the id=ID attribute.
> 1594 */
> 1595 if( markup.iCode==MARKUP_DIV ){
> 1596 pushStackWithId(&renderer, markup.iCode, markupId(&markup),
> 1597 (renderer.state & ALLOW_WIKI)!=0);
> 1598 }else
> 1599
> 1600 /* Enter <verbatim> processing. With verbatim enabled, all other
> 1601 ** markup other than the corresponding end-tag with the same ID is
> 1602 ** ignored.
> 1603 */
> 1604 if( markup.iCode==MARKUP_VERBATIM ){
> 1605 int vAttrIdx, vAttrDidAppend=0;
> 1606 renderer.zVerbatimId = 0;
> 1607 renderer.inVerbatim = 1;
> 1608 renderer.preVerbState = renderer.state;
> 1609 renderer.state &= ~ALLOW_WIKI;
> 1610 for (vAttrIdx = 0; vAttrIdx < markup.nAttr; vAttrIdx++){
> 1611 if( markup.aAttr[vAttrIdx].iACode == ATTR_ID ){
> 1612 renderer.zVerbatimId = markup.aAttr[0].zValue;
> 1613 }else if( markup.aAttr[vAttrIdx].iACode == ATTR_TYPE ){
> 1614 vAttrDidAppend=1;
> 1615 }
> 1616 }
> 1617 renderer.wantAutoParagraph = 0;
> 1618 }
> 1619
> 1620 /* Restore the input text to its original configuration
> 1621 */
> 1622 unparseMarkup(&markup);
> 1623 break;
> 1624 }
> 1625 default: {
> 1626 break;
> 1627 }
> 1628 }
> 1629 z += n;
> 1630 }
1451 } 1631 }