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
- branch=trunk inherited from [a28c83647d]
- sym-trunk inherited from [a28c83647d]
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 | } | |