Fossil SCM
Rework forum post serial IDs to include a revision number when edited. This fixes buggy sids displayed in thread [https://fossil-scm.org/forum/forumpost/6737a387fe?t=c&threadtable].
Commit
dd47b8c311ab4765bf1deb5749199b1ae6f4a87ca077da2f1054dfe4093e4e59
Parent
df7b0c31868613c…
2 files changed
+41
-14
+11
-1
+41
-14
| --- src/forum.c | ||
| +++ src/forum.c | ||
| @@ -33,19 +33,21 @@ | ||
| 33 | 33 | ** a reply. |
| 34 | 34 | */ |
| 35 | 35 | struct ForumEntry { |
| 36 | 36 | int fpid; /* rid for this entry */ |
| 37 | 37 | int sid; /* Serial ID number */ |
| 38 | + int rev; /* Revision number */ | |
| 38 | 39 | char *zUuid; /* Artifact hash */ |
| 39 | 40 | ForumEntry *pIrt; /* This entry replies to pIrt */ |
| 40 | 41 | ForumEntry *pEditHead; /* Original, unedited entry */ |
| 41 | 42 | ForumEntry *pEditTail; /* Most recent edit for this entry */ |
| 42 | 43 | ForumEntry *pEditNext; /* This entry is edited by pEditNext */ |
| 43 | 44 | ForumEntry *pEditPrev; /* This entry is an edit of pEditPrev */ |
| 44 | 45 | ForumEntry *pNext; /* Next in chronological order */ |
| 45 | 46 | ForumEntry *pPrev; /* Previous in chronological order */ |
| 46 | 47 | ForumEntry *pDisplay; /* Next in display order */ |
| 48 | + int nEdit; /* Number of edits to this entry */ | |
| 47 | 49 | int nIndent; /* Number of levels of indentation for this entry */ |
| 48 | 50 | }; |
| 49 | 51 | |
| 50 | 52 | /* |
| 51 | 53 | ** A single instance of the following tracks all entries for a thread. |
| @@ -175,37 +177,46 @@ | ||
| 175 | 177 | memset(pEntry, 0, sizeof(*pEntry)); |
| 176 | 178 | pEntry->fpid = db_column_int(&q, 0); |
| 177 | 179 | firt = db_column_int(&q, 1); |
| 178 | 180 | fprev = db_column_int(&q, 2); |
| 179 | 181 | pEntry->zUuid = fossil_strdup(db_column_text(&q,3)); |
| 180 | - pEntry->sid = sid++; | |
| 182 | + if( !fprev ) pEntry->sid = sid++; | |
| 181 | 183 | pEntry->pPrev = pThread->pLast; |
| 182 | 184 | pEntry->pNext = 0; |
| 183 | 185 | if( pThread->pLast==0 ){ |
| 184 | 186 | pThread->pFirst = pEntry; |
| 185 | 187 | }else{ |
| 186 | 188 | pThread->pLast->pNext = pEntry; |
| 187 | 189 | } |
| 190 | + pThread->pLast = pEntry; | |
| 191 | + | |
| 192 | + /* Find the in-reply-to post. Default to the topic post if the replied-to | |
| 193 | + ** post cannot be found. */ | |
| 188 | 194 | if( firt ){ |
| 189 | 195 | pEntry->pIrt = pThread->pFirst; |
| 190 | 196 | for(p=pThread->pFirst; p; p=p->pNext){ |
| 191 | 197 | if( p->fpid==firt ){ |
| 192 | 198 | pEntry->pIrt = p; |
| 193 | 199 | break; |
| 194 | 200 | } |
| 195 | 201 | } |
| 196 | 202 | } |
| 203 | + | |
| 204 | + /* Maintain the linked list of post edits. */ | |
| 197 | 205 | if( fprev ){ |
| 198 | 206 | p = forumentry_backward(pEntry->pPrev, fprev); |
| 199 | 207 | p->pEditNext = pEntry; |
| 208 | + pEntry->sid = p->sid; | |
| 209 | + pEntry->rev = p->rev+1; | |
| 210 | + pEntry->nEdit = p->nEdit+1; | |
| 200 | 211 | pEntry->pEditPrev = p; |
| 201 | 212 | pEntry->pEditHead = p->pEditHead ? p->pEditHead : p; |
| 202 | 213 | for(; p; p=p->pEditPrev ){ |
| 214 | + p->nEdit = pEntry->nEdit; | |
| 203 | 215 | p->pEditTail = pEntry; |
| 204 | 216 | } |
| 205 | 217 | } |
| 206 | - pThread->pLast = pEntry; | |
| 207 | 218 | } |
| 208 | 219 | db_finalize(&q); |
| 209 | 220 | |
| 210 | 221 | if( computeHierarchy ){ |
| 211 | 222 | /* Compute the hierarchical display order */ |
| @@ -287,13 +298,13 @@ | ||
| 287 | 298 | pThread = forumthread_create(froot, 1); |
| 288 | 299 | fossil_print("Chronological:\n"); |
| 289 | 300 | fossil_print( |
| 290 | 301 | /* 0 1 2 3 4 5 6 7 */ |
| 291 | 302 | /* 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123 */ |
| 292 | - " sid fpid pIrt pEditPrev pEditTail hash\n"); | |
| 303 | + " sid rev fpid pIrt pEditPrev pEditTail hash\n"); | |
| 293 | 304 | for(p=pThread->pFirst; p; p=p->pNext){ |
| 294 | - fossil_print("%4d %9d %9d %9d %9d %8.8s\n", p->sid, | |
| 305 | + fossil_print("%4d %4d %9d %9d %9d %9d %8.8s\n", p->sid, p->rev, | |
| 295 | 306 | p->fpid, p->pIrt ? p->pIrt->fpid : 0, |
| 296 | 307 | p->pEditPrev ? p->pEditPrev->fpid : 0, |
| 297 | 308 | p->pEditTail ? p->pEditTail->fpid : 0, p->zUuid); |
| 298 | 309 | } |
| 299 | 310 | fossil_print("\nDisplay\n"); |
| @@ -412,11 +423,10 @@ | ||
| 412 | 423 | Manifest *pPost; |
| 413 | 424 | int isPrivate; /* True for posts awaiting moderation */ |
| 414 | 425 | int sameUser; /* True if author is also the reader */ |
| 415 | 426 | const char *zUuid; |
| 416 | 427 | char *zDisplayName; /* The display name */ |
| 417 | - int sid; | |
| 418 | 428 | |
| 419 | 429 | pPost = manifest_get(p->fpid, CFTYPE_FORUM, 0); |
| 420 | 430 | if( pPost==0 ) continue; |
| 421 | 431 | if( p->fpid==target ){ |
| 422 | 432 | @ <div id="forum%d(p->fpid)" class="forumTime forumSel"> |
| @@ -428,30 +438,39 @@ | ||
| 428 | 438 | if( pPost->zThreadTitle ){ |
| 429 | 439 | @ <h1>%h(pPost->zThreadTitle)</h1> |
| 430 | 440 | } |
| 431 | 441 | zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate); |
| 432 | 442 | zDisplayName = display_name_from_login(pPost->zUser); |
| 433 | - sid = p->pEditPrev ? p->pEditPrev->sid : p->sid; | |
| 434 | - @ <h3 class='forumPostHdr'>(%d(sid)) By %h(zDisplayName) on %h(zDate) | |
| 443 | + @ <h3 class='forumPostHdr'>(%d(p->sid)\ | |
| 444 | + if( p->nEdit ){ | |
| 445 | + @ .%.*d(fossil_num_digits(p->nEdit))(p->rev)\ | |
| 446 | + } | |
| 447 | + @ ) By %h(zDisplayName) on %h(zDate) | |
| 435 | 448 | fossil_free(zDisplayName); |
| 436 | 449 | fossil_free(zDate); |
| 437 | 450 | if( p->pEditPrev ){ |
| 438 | 451 | @ edit of %z(href("%R/forumpost/%S?t=%c",p->pEditPrev->zUuid,cMode))\ |
| 439 | - @ %d(p->pEditPrev->sid)</a> | |
| 452 | + @ %d(p->pEditPrev->sid)\ | |
| 453 | + @ .%.*d(fossil_num_digits(p->nEdit))(p->pEditPrev->rev)</a> | |
| 440 | 454 | } |
| 441 | 455 | if( g.perm.Debug ){ |
| 442 | 456 | @ <span class="debug">\ |
| 443 | 457 | @ <a href="%R/artifact/%h(p->zUuid)">(artifact-%d(p->fpid))</a></span> |
| 444 | 458 | } |
| 445 | 459 | if( p->pIrt ){ |
| 446 | 460 | @ in reply to %z(href("%R/forumpost/%S?t=%c",p->pIrt->zUuid,cMode))\ |
| 447 | - @ %d(p->pIrt->sid)</a> | |
| 461 | + @ %d(p->pIrt->sid)\ | |
| 462 | + if( p->pIrt->nEdit ){ | |
| 463 | + @ .%.*d(fossil_num_digits(p->pIrt->nEdit))(p->pIrt->rev)\ | |
| 464 | + } | |
| 465 | + @ </a> | |
| 448 | 466 | } |
| 449 | 467 | zUuid = p->zUuid; |
| 450 | 468 | if( p->pEditTail ){ |
| 451 | 469 | @ updated by %z(href("%R/forumpost/%S?t=%c",p->pEditTail->zUuid,cMode))\ |
| 452 | - @ %d(p->pEditTail->sid)</a> | |
| 470 | + @ %d(p->pEditTail->sid)\ | |
| 471 | + @ .%.*d(fossil_num_digits(p->nEdit))(p->pEditTail->rev)</a> | |
| 453 | 472 | zUuid = p->pEditTail->zUuid; |
| 454 | 473 | } |
| 455 | 474 | if( p->fpid!=target ){ |
| 456 | 475 | @ %z(href("%R/forumpost/%S?t=%c",zUuid,cMode))[link]</a> |
| 457 | 476 | } |
| @@ -508,14 +527,14 @@ | ||
| 508 | 527 | ** to be displayed for debugging purposes. |
| 509 | 528 | */ |
| 510 | 529 | if( PB("threadtable") ){ |
| 511 | 530 | @ <hr> |
| 512 | 531 | @ <table border="1" cellpadding="3" cellspacing="0"> |
| 513 | - @ <tr><th>sid<th>fpid<th>pIrt<th>pEditHead<th>pEditTail\ | |
| 532 | + @ <tr><th>sid<th>rev<th>fpid<th>pIrt<th>pEditHead<th>pEditTail\ | |
| 514 | 533 | @ <th>pEditNext<th>pEditPrev<th>hash |
| 515 | 534 | for(p=pThread->pFirst; p; p=p->pNext){ |
| 516 | - @ <tr><td>%d(p->sid)<td>%d(p->fpid)\ | |
| 535 | + @ <tr><td>%d(p->sid)<td>%d(p->rev)<td>%d(p->fpid)\ | |
| 517 | 536 | @ <td>%d(p->pIrt?p->pIrt->fpid:0)\ |
| 518 | 537 | @ <td>%d(p->pEditHead?p->pEditHead->fpid:0)\ |
| 519 | 538 | @ <td>%d(p->pEditTail?p->pEditTail->fpid:0)\ |
| 520 | 539 | @ <td>%d(p->pEditNext?p->pEditNext->fpid:0)\ |
| 521 | 540 | @ <td>%d(p->pEditPrev?p->pEditPrev->fpid:0)\ |
| @@ -555,20 +574,28 @@ | ||
| 555 | 574 | pPost = manifest_get(p->fpid, CFTYPE_FORUM, 0); |
| 556 | 575 | if( pPost==0 ) continue; |
| 557 | 576 | @ <div id="forum%d(p->fpid)" class="forumTime"> |
| 558 | 577 | zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate); |
| 559 | 578 | zDisplayName = display_name_from_login(pPost->zUser); |
| 560 | - @ <h3 class='forumPostHdr'>(%d(p->sid)) By %h(zDisplayName) on %h(zDate) | |
| 579 | + @ <h3 class='forumPostHdr'>(%d(p->sid)\ | |
| 580 | + if( p->nEdit ){ | |
| 581 | + @ .%.*d(fossil_num_digits(p->nEdit))(p->rev)\ | |
| 582 | + } | |
| 583 | + @ ) By %h(zDisplayName) on %h(zDate) | |
| 561 | 584 | fossil_free(zDisplayName); |
| 562 | 585 | fossil_free(zDate); |
| 563 | 586 | if( g.perm.Debug ){ |
| 564 | 587 | @ <span class="debug">\ |
| 565 | 588 | @ <a href="%R/artifact/%h(p->zUuid)">(artifact-%d(p->fpid))</a></span> |
| 566 | 589 | } |
| 567 | 590 | if( p->pIrt && cnt==1 ){ |
| 568 | 591 | @ in reply to %z(href("%R/forumpost/%S?t=%c",p->pIrt->zUuid,cMode))\ |
| 569 | - @ %d(p->pIrt->sid)</a> | |
| 592 | + @ %d(p->pIrt->sid)\ | |
| 593 | + if( p->pIrt->nEdit ){ | |
| 594 | + @ .%.*d(fossil_num_digits(p->pIrt->nEdit))(p->pIrt->rev)\ | |
| 595 | + } | |
| 596 | + @ </a> | |
| 570 | 597 | } |
| 571 | 598 | zUuid = p->zUuid; |
| 572 | 599 | @ %z(href("%R/forumpost/%S?t=c",zUuid))[link]</a> |
| 573 | 600 | if( !bRawMode ){ |
| 574 | 601 | @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a> |
| 575 | 602 |
| --- src/forum.c | |
| +++ src/forum.c | |
| @@ -33,19 +33,21 @@ | |
| 33 | ** a reply. |
| 34 | */ |
| 35 | struct ForumEntry { |
| 36 | int fpid; /* rid for this entry */ |
| 37 | int sid; /* Serial ID number */ |
| 38 | char *zUuid; /* Artifact hash */ |
| 39 | ForumEntry *pIrt; /* This entry replies to pIrt */ |
| 40 | ForumEntry *pEditHead; /* Original, unedited entry */ |
| 41 | ForumEntry *pEditTail; /* Most recent edit for this entry */ |
| 42 | ForumEntry *pEditNext; /* This entry is edited by pEditNext */ |
| 43 | ForumEntry *pEditPrev; /* This entry is an edit of pEditPrev */ |
| 44 | ForumEntry *pNext; /* Next in chronological order */ |
| 45 | ForumEntry *pPrev; /* Previous in chronological order */ |
| 46 | ForumEntry *pDisplay; /* Next in display order */ |
| 47 | int nIndent; /* Number of levels of indentation for this entry */ |
| 48 | }; |
| 49 | |
| 50 | /* |
| 51 | ** A single instance of the following tracks all entries for a thread. |
| @@ -175,37 +177,46 @@ | |
| 175 | memset(pEntry, 0, sizeof(*pEntry)); |
| 176 | pEntry->fpid = db_column_int(&q, 0); |
| 177 | firt = db_column_int(&q, 1); |
| 178 | fprev = db_column_int(&q, 2); |
| 179 | pEntry->zUuid = fossil_strdup(db_column_text(&q,3)); |
| 180 | pEntry->sid = sid++; |
| 181 | pEntry->pPrev = pThread->pLast; |
| 182 | pEntry->pNext = 0; |
| 183 | if( pThread->pLast==0 ){ |
| 184 | pThread->pFirst = pEntry; |
| 185 | }else{ |
| 186 | pThread->pLast->pNext = pEntry; |
| 187 | } |
| 188 | if( firt ){ |
| 189 | pEntry->pIrt = pThread->pFirst; |
| 190 | for(p=pThread->pFirst; p; p=p->pNext){ |
| 191 | if( p->fpid==firt ){ |
| 192 | pEntry->pIrt = p; |
| 193 | break; |
| 194 | } |
| 195 | } |
| 196 | } |
| 197 | if( fprev ){ |
| 198 | p = forumentry_backward(pEntry->pPrev, fprev); |
| 199 | p->pEditNext = pEntry; |
| 200 | pEntry->pEditPrev = p; |
| 201 | pEntry->pEditHead = p->pEditHead ? p->pEditHead : p; |
| 202 | for(; p; p=p->pEditPrev ){ |
| 203 | p->pEditTail = pEntry; |
| 204 | } |
| 205 | } |
| 206 | pThread->pLast = pEntry; |
| 207 | } |
| 208 | db_finalize(&q); |
| 209 | |
| 210 | if( computeHierarchy ){ |
| 211 | /* Compute the hierarchical display order */ |
| @@ -287,13 +298,13 @@ | |
| 287 | pThread = forumthread_create(froot, 1); |
| 288 | fossil_print("Chronological:\n"); |
| 289 | fossil_print( |
| 290 | /* 0 1 2 3 4 5 6 7 */ |
| 291 | /* 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123 */ |
| 292 | " sid fpid pIrt pEditPrev pEditTail hash\n"); |
| 293 | for(p=pThread->pFirst; p; p=p->pNext){ |
| 294 | fossil_print("%4d %9d %9d %9d %9d %8.8s\n", p->sid, |
| 295 | p->fpid, p->pIrt ? p->pIrt->fpid : 0, |
| 296 | p->pEditPrev ? p->pEditPrev->fpid : 0, |
| 297 | p->pEditTail ? p->pEditTail->fpid : 0, p->zUuid); |
| 298 | } |
| 299 | fossil_print("\nDisplay\n"); |
| @@ -412,11 +423,10 @@ | |
| 412 | Manifest *pPost; |
| 413 | int isPrivate; /* True for posts awaiting moderation */ |
| 414 | int sameUser; /* True if author is also the reader */ |
| 415 | const char *zUuid; |
| 416 | char *zDisplayName; /* The display name */ |
| 417 | int sid; |
| 418 | |
| 419 | pPost = manifest_get(p->fpid, CFTYPE_FORUM, 0); |
| 420 | if( pPost==0 ) continue; |
| 421 | if( p->fpid==target ){ |
| 422 | @ <div id="forum%d(p->fpid)" class="forumTime forumSel"> |
| @@ -428,30 +438,39 @@ | |
| 428 | if( pPost->zThreadTitle ){ |
| 429 | @ <h1>%h(pPost->zThreadTitle)</h1> |
| 430 | } |
| 431 | zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate); |
| 432 | zDisplayName = display_name_from_login(pPost->zUser); |
| 433 | sid = p->pEditPrev ? p->pEditPrev->sid : p->sid; |
| 434 | @ <h3 class='forumPostHdr'>(%d(sid)) By %h(zDisplayName) on %h(zDate) |
| 435 | fossil_free(zDisplayName); |
| 436 | fossil_free(zDate); |
| 437 | if( p->pEditPrev ){ |
| 438 | @ edit of %z(href("%R/forumpost/%S?t=%c",p->pEditPrev->zUuid,cMode))\ |
| 439 | @ %d(p->pEditPrev->sid)</a> |
| 440 | } |
| 441 | if( g.perm.Debug ){ |
| 442 | @ <span class="debug">\ |
| 443 | @ <a href="%R/artifact/%h(p->zUuid)">(artifact-%d(p->fpid))</a></span> |
| 444 | } |
| 445 | if( p->pIrt ){ |
| 446 | @ in reply to %z(href("%R/forumpost/%S?t=%c",p->pIrt->zUuid,cMode))\ |
| 447 | @ %d(p->pIrt->sid)</a> |
| 448 | } |
| 449 | zUuid = p->zUuid; |
| 450 | if( p->pEditTail ){ |
| 451 | @ updated by %z(href("%R/forumpost/%S?t=%c",p->pEditTail->zUuid,cMode))\ |
| 452 | @ %d(p->pEditTail->sid)</a> |
| 453 | zUuid = p->pEditTail->zUuid; |
| 454 | } |
| 455 | if( p->fpid!=target ){ |
| 456 | @ %z(href("%R/forumpost/%S?t=%c",zUuid,cMode))[link]</a> |
| 457 | } |
| @@ -508,14 +527,14 @@ | |
| 508 | ** to be displayed for debugging purposes. |
| 509 | */ |
| 510 | if( PB("threadtable") ){ |
| 511 | @ <hr> |
| 512 | @ <table border="1" cellpadding="3" cellspacing="0"> |
| 513 | @ <tr><th>sid<th>fpid<th>pIrt<th>pEditHead<th>pEditTail\ |
| 514 | @ <th>pEditNext<th>pEditPrev<th>hash |
| 515 | for(p=pThread->pFirst; p; p=p->pNext){ |
| 516 | @ <tr><td>%d(p->sid)<td>%d(p->fpid)\ |
| 517 | @ <td>%d(p->pIrt?p->pIrt->fpid:0)\ |
| 518 | @ <td>%d(p->pEditHead?p->pEditHead->fpid:0)\ |
| 519 | @ <td>%d(p->pEditTail?p->pEditTail->fpid:0)\ |
| 520 | @ <td>%d(p->pEditNext?p->pEditNext->fpid:0)\ |
| 521 | @ <td>%d(p->pEditPrev?p->pEditPrev->fpid:0)\ |
| @@ -555,20 +574,28 @@ | |
| 555 | pPost = manifest_get(p->fpid, CFTYPE_FORUM, 0); |
| 556 | if( pPost==0 ) continue; |
| 557 | @ <div id="forum%d(p->fpid)" class="forumTime"> |
| 558 | zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate); |
| 559 | zDisplayName = display_name_from_login(pPost->zUser); |
| 560 | @ <h3 class='forumPostHdr'>(%d(p->sid)) By %h(zDisplayName) on %h(zDate) |
| 561 | fossil_free(zDisplayName); |
| 562 | fossil_free(zDate); |
| 563 | if( g.perm.Debug ){ |
| 564 | @ <span class="debug">\ |
| 565 | @ <a href="%R/artifact/%h(p->zUuid)">(artifact-%d(p->fpid))</a></span> |
| 566 | } |
| 567 | if( p->pIrt && cnt==1 ){ |
| 568 | @ in reply to %z(href("%R/forumpost/%S?t=%c",p->pIrt->zUuid,cMode))\ |
| 569 | @ %d(p->pIrt->sid)</a> |
| 570 | } |
| 571 | zUuid = p->zUuid; |
| 572 | @ %z(href("%R/forumpost/%S?t=c",zUuid))[link]</a> |
| 573 | if( !bRawMode ){ |
| 574 | @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a> |
| 575 |
| --- src/forum.c | |
| +++ src/forum.c | |
| @@ -33,19 +33,21 @@ | |
| 33 | ** a reply. |
| 34 | */ |
| 35 | struct ForumEntry { |
| 36 | int fpid; /* rid for this entry */ |
| 37 | int sid; /* Serial ID number */ |
| 38 | int rev; /* Revision number */ |
| 39 | char *zUuid; /* Artifact hash */ |
| 40 | ForumEntry *pIrt; /* This entry replies to pIrt */ |
| 41 | ForumEntry *pEditHead; /* Original, unedited entry */ |
| 42 | ForumEntry *pEditTail; /* Most recent edit for this entry */ |
| 43 | ForumEntry *pEditNext; /* This entry is edited by pEditNext */ |
| 44 | ForumEntry *pEditPrev; /* This entry is an edit of pEditPrev */ |
| 45 | ForumEntry *pNext; /* Next in chronological order */ |
| 46 | ForumEntry *pPrev; /* Previous in chronological order */ |
| 47 | ForumEntry *pDisplay; /* Next in display order */ |
| 48 | int nEdit; /* Number of edits to this entry */ |
| 49 | int nIndent; /* Number of levels of indentation for this entry */ |
| 50 | }; |
| 51 | |
| 52 | /* |
| 53 | ** A single instance of the following tracks all entries for a thread. |
| @@ -175,37 +177,46 @@ | |
| 177 | memset(pEntry, 0, sizeof(*pEntry)); |
| 178 | pEntry->fpid = db_column_int(&q, 0); |
| 179 | firt = db_column_int(&q, 1); |
| 180 | fprev = db_column_int(&q, 2); |
| 181 | pEntry->zUuid = fossil_strdup(db_column_text(&q,3)); |
| 182 | if( !fprev ) pEntry->sid = sid++; |
| 183 | pEntry->pPrev = pThread->pLast; |
| 184 | pEntry->pNext = 0; |
| 185 | if( pThread->pLast==0 ){ |
| 186 | pThread->pFirst = pEntry; |
| 187 | }else{ |
| 188 | pThread->pLast->pNext = pEntry; |
| 189 | } |
| 190 | pThread->pLast = pEntry; |
| 191 | |
| 192 | /* Find the in-reply-to post. Default to the topic post if the replied-to |
| 193 | ** post cannot be found. */ |
| 194 | if( firt ){ |
| 195 | pEntry->pIrt = pThread->pFirst; |
| 196 | for(p=pThread->pFirst; p; p=p->pNext){ |
| 197 | if( p->fpid==firt ){ |
| 198 | pEntry->pIrt = p; |
| 199 | break; |
| 200 | } |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | /* Maintain the linked list of post edits. */ |
| 205 | if( fprev ){ |
| 206 | p = forumentry_backward(pEntry->pPrev, fprev); |
| 207 | p->pEditNext = pEntry; |
| 208 | pEntry->sid = p->sid; |
| 209 | pEntry->rev = p->rev+1; |
| 210 | pEntry->nEdit = p->nEdit+1; |
| 211 | pEntry->pEditPrev = p; |
| 212 | pEntry->pEditHead = p->pEditHead ? p->pEditHead : p; |
| 213 | for(; p; p=p->pEditPrev ){ |
| 214 | p->nEdit = pEntry->nEdit; |
| 215 | p->pEditTail = pEntry; |
| 216 | } |
| 217 | } |
| 218 | } |
| 219 | db_finalize(&q); |
| 220 | |
| 221 | if( computeHierarchy ){ |
| 222 | /* Compute the hierarchical display order */ |
| @@ -287,13 +298,13 @@ | |
| 298 | pThread = forumthread_create(froot, 1); |
| 299 | fossil_print("Chronological:\n"); |
| 300 | fossil_print( |
| 301 | /* 0 1 2 3 4 5 6 7 */ |
| 302 | /* 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123 */ |
| 303 | " sid rev fpid pIrt pEditPrev pEditTail hash\n"); |
| 304 | for(p=pThread->pFirst; p; p=p->pNext){ |
| 305 | fossil_print("%4d %4d %9d %9d %9d %9d %8.8s\n", p->sid, p->rev, |
| 306 | p->fpid, p->pIrt ? p->pIrt->fpid : 0, |
| 307 | p->pEditPrev ? p->pEditPrev->fpid : 0, |
| 308 | p->pEditTail ? p->pEditTail->fpid : 0, p->zUuid); |
| 309 | } |
| 310 | fossil_print("\nDisplay\n"); |
| @@ -412,11 +423,10 @@ | |
| 423 | Manifest *pPost; |
| 424 | int isPrivate; /* True for posts awaiting moderation */ |
| 425 | int sameUser; /* True if author is also the reader */ |
| 426 | const char *zUuid; |
| 427 | char *zDisplayName; /* The display name */ |
| 428 | |
| 429 | pPost = manifest_get(p->fpid, CFTYPE_FORUM, 0); |
| 430 | if( pPost==0 ) continue; |
| 431 | if( p->fpid==target ){ |
| 432 | @ <div id="forum%d(p->fpid)" class="forumTime forumSel"> |
| @@ -428,30 +438,39 @@ | |
| 438 | if( pPost->zThreadTitle ){ |
| 439 | @ <h1>%h(pPost->zThreadTitle)</h1> |
| 440 | } |
| 441 | zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate); |
| 442 | zDisplayName = display_name_from_login(pPost->zUser); |
| 443 | @ <h3 class='forumPostHdr'>(%d(p->sid)\ |
| 444 | if( p->nEdit ){ |
| 445 | @ .%.*d(fossil_num_digits(p->nEdit))(p->rev)\ |
| 446 | } |
| 447 | @ ) By %h(zDisplayName) on %h(zDate) |
| 448 | fossil_free(zDisplayName); |
| 449 | fossil_free(zDate); |
| 450 | if( p->pEditPrev ){ |
| 451 | @ edit of %z(href("%R/forumpost/%S?t=%c",p->pEditPrev->zUuid,cMode))\ |
| 452 | @ %d(p->pEditPrev->sid)\ |
| 453 | @ .%.*d(fossil_num_digits(p->nEdit))(p->pEditPrev->rev)</a> |
| 454 | } |
| 455 | if( g.perm.Debug ){ |
| 456 | @ <span class="debug">\ |
| 457 | @ <a href="%R/artifact/%h(p->zUuid)">(artifact-%d(p->fpid))</a></span> |
| 458 | } |
| 459 | if( p->pIrt ){ |
| 460 | @ in reply to %z(href("%R/forumpost/%S?t=%c",p->pIrt->zUuid,cMode))\ |
| 461 | @ %d(p->pIrt->sid)\ |
| 462 | if( p->pIrt->nEdit ){ |
| 463 | @ .%.*d(fossil_num_digits(p->pIrt->nEdit))(p->pIrt->rev)\ |
| 464 | } |
| 465 | @ </a> |
| 466 | } |
| 467 | zUuid = p->zUuid; |
| 468 | if( p->pEditTail ){ |
| 469 | @ updated by %z(href("%R/forumpost/%S?t=%c",p->pEditTail->zUuid,cMode))\ |
| 470 | @ %d(p->pEditTail->sid)\ |
| 471 | @ .%.*d(fossil_num_digits(p->nEdit))(p->pEditTail->rev)</a> |
| 472 | zUuid = p->pEditTail->zUuid; |
| 473 | } |
| 474 | if( p->fpid!=target ){ |
| 475 | @ %z(href("%R/forumpost/%S?t=%c",zUuid,cMode))[link]</a> |
| 476 | } |
| @@ -508,14 +527,14 @@ | |
| 527 | ** to be displayed for debugging purposes. |
| 528 | */ |
| 529 | if( PB("threadtable") ){ |
| 530 | @ <hr> |
| 531 | @ <table border="1" cellpadding="3" cellspacing="0"> |
| 532 | @ <tr><th>sid<th>rev<th>fpid<th>pIrt<th>pEditHead<th>pEditTail\ |
| 533 | @ <th>pEditNext<th>pEditPrev<th>hash |
| 534 | for(p=pThread->pFirst; p; p=p->pNext){ |
| 535 | @ <tr><td>%d(p->sid)<td>%d(p->rev)<td>%d(p->fpid)\ |
| 536 | @ <td>%d(p->pIrt?p->pIrt->fpid:0)\ |
| 537 | @ <td>%d(p->pEditHead?p->pEditHead->fpid:0)\ |
| 538 | @ <td>%d(p->pEditTail?p->pEditTail->fpid:0)\ |
| 539 | @ <td>%d(p->pEditNext?p->pEditNext->fpid:0)\ |
| 540 | @ <td>%d(p->pEditPrev?p->pEditPrev->fpid:0)\ |
| @@ -555,20 +574,28 @@ | |
| 574 | pPost = manifest_get(p->fpid, CFTYPE_FORUM, 0); |
| 575 | if( pPost==0 ) continue; |
| 576 | @ <div id="forum%d(p->fpid)" class="forumTime"> |
| 577 | zDate = db_text(0, "SELECT datetime(%.17g)", pPost->rDate); |
| 578 | zDisplayName = display_name_from_login(pPost->zUser); |
| 579 | @ <h3 class='forumPostHdr'>(%d(p->sid)\ |
| 580 | if( p->nEdit ){ |
| 581 | @ .%.*d(fossil_num_digits(p->nEdit))(p->rev)\ |
| 582 | } |
| 583 | @ ) By %h(zDisplayName) on %h(zDate) |
| 584 | fossil_free(zDisplayName); |
| 585 | fossil_free(zDate); |
| 586 | if( g.perm.Debug ){ |
| 587 | @ <span class="debug">\ |
| 588 | @ <a href="%R/artifact/%h(p->zUuid)">(artifact-%d(p->fpid))</a></span> |
| 589 | } |
| 590 | if( p->pIrt && cnt==1 ){ |
| 591 | @ in reply to %z(href("%R/forumpost/%S?t=%c",p->pIrt->zUuid,cMode))\ |
| 592 | @ %d(p->pIrt->sid)\ |
| 593 | if( p->pIrt->nEdit ){ |
| 594 | @ .%.*d(fossil_num_digits(p->pIrt->nEdit))(p->pIrt->rev)\ |
| 595 | } |
| 596 | @ </a> |
| 597 | } |
| 598 | zUuid = p->zUuid; |
| 599 | @ %z(href("%R/forumpost/%S?t=c",zUuid))[link]</a> |
| 600 | if( !bRawMode ){ |
| 601 | @ %z(href("%R/forumpost/%S?raw",zUuid))[source]</a> |
| 602 |
+11
-1
| --- src/util.c | ||
| +++ src/util.c | ||
| @@ -691,11 +691,11 @@ | ||
| 691 | 691 | int i; |
| 692 | 692 | char z[60]; |
| 693 | 693 | |
| 694 | 694 | /* Source characters for the password. Omit characters like "0", "O", |
| 695 | 695 | ** "1" and "I" that might be easily confused */ |
| 696 | - static const char zAlphabet[] = | |
| 696 | + static const char zAlphabet[] = | |
| 697 | 697 | /* 0 1 2 3 4 5 */ |
| 698 | 698 | /* 123456789 123456789 123456789 123456789 123456789 123456 */ |
| 699 | 699 | "23456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"; |
| 700 | 700 | |
| 701 | 701 | if( N<8 ) N = 8; |
| @@ -728,5 +728,15 @@ | ||
| 728 | 728 | if( g.argc>=3 ){ |
| 729 | 729 | N = atoi(g.argv[2]); |
| 730 | 730 | } |
| 731 | 731 | fossil_print("%s\n", fossil_random_password(N)); |
| 732 | 732 | } |
| 733 | + | |
| 734 | +/* | |
| 735 | +** Return the number of decimal digits in a nonnegative integer. This is useful | |
| 736 | +** when formatting text. | |
| 737 | +*/ | |
| 738 | +int fossil_num_digits(int n){ | |
| 739 | + return n< 10 ? 1 : n< 100 ? 2 : n< 1000 ? 3 | |
| 740 | + : n< 10000 ? 4 : n< 100000 ? 5 : n< 1000000 ? 6 | |
| 741 | + : n<10000000 ? 7 : n<100000000 ? 8 : n<1000000000 ? 9 : 10; | |
| 742 | +} | |
| 733 | 743 |
| --- src/util.c | |
| +++ src/util.c | |
| @@ -691,11 +691,11 @@ | |
| 691 | int i; |
| 692 | char z[60]; |
| 693 | |
| 694 | /* Source characters for the password. Omit characters like "0", "O", |
| 695 | ** "1" and "I" that might be easily confused */ |
| 696 | static const char zAlphabet[] = |
| 697 | /* 0 1 2 3 4 5 */ |
| 698 | /* 123456789 123456789 123456789 123456789 123456789 123456 */ |
| 699 | "23456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"; |
| 700 | |
| 701 | if( N<8 ) N = 8; |
| @@ -728,5 +728,15 @@ | |
| 728 | if( g.argc>=3 ){ |
| 729 | N = atoi(g.argv[2]); |
| 730 | } |
| 731 | fossil_print("%s\n", fossil_random_password(N)); |
| 732 | } |
| 733 |
| --- src/util.c | |
| +++ src/util.c | |
| @@ -691,11 +691,11 @@ | |
| 691 | int i; |
| 692 | char z[60]; |
| 693 | |
| 694 | /* Source characters for the password. Omit characters like "0", "O", |
| 695 | ** "1" and "I" that might be easily confused */ |
| 696 | static const char zAlphabet[] = |
| 697 | /* 0 1 2 3 4 5 */ |
| 698 | /* 123456789 123456789 123456789 123456789 123456789 123456 */ |
| 699 | "23456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"; |
| 700 | |
| 701 | if( N<8 ) N = 8; |
| @@ -728,5 +728,15 @@ | |
| 728 | if( g.argc>=3 ){ |
| 729 | N = atoi(g.argv[2]); |
| 730 | } |
| 731 | fossil_print("%s\n", fossil_random_password(N)); |
| 732 | } |
| 733 | |
| 734 | /* |
| 735 | ** Return the number of decimal digits in a nonnegative integer. This is useful |
| 736 | ** when formatting text. |
| 737 | */ |
| 738 | int fossil_num_digits(int n){ |
| 739 | return n< 10 ? 1 : n< 100 ? 2 : n< 1000 ? 3 |
| 740 | : n< 10000 ? 4 : n< 100000 ? 5 : n< 1000000 ? 6 |
| 741 | : n<10000000 ? 7 : n<100000000 ? 8 : n<1000000000 ? 9 : 10; |
| 742 | } |
| 743 |