Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Merged to [ed26056bb5]. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
588bb7cd734d4c3a066a715249f8498f |
| User & Date: | aku 2008-02-24 18:50:35.000 |
Context
|
2008-02-24
| ||
| 21:51 | Add a human-readable description on each timeline. Add the "ancestors" and "decendents" links on the baseline information pages, making it easier to understand the context of a baseline. ... (check-in: e38c89130f user: drh tags: trunk) | |
| 18:50 | Merged to [ed26056bb5]. ... (check-in: 588bb7cd73 user: aku tags: trunk) | |
| 18:01 | Updated my notes regarding memory usage. Converted more locations to incremental query processing via 'state foreachrow', now throughout the importer. ... (check-in: f637d42206 user: aku tags: trunk) | |
|
2008-02-21
| ||
| 16:16 | fixed a small copy/paste error in /setup_ticket ... (check-in: ed26056bb5 user: wanderi1 tags: trunk) | |
Changes
Changes to src/blob.c.
| ︙ | ︙ | |||
239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
** pBig in order to cause p to be nul-terminated. If pBig
** should not be modified, then use blob_str() instead of this
** routine. blob_str() will make a copy of the p if necessary
** to avoid modifying pBig.
*/
char *blob_terminate(Blob *p){
blob_is_init(p);
p->aData[p->nUsed] = 0;
return p->aData;
}
/*
** Compare two blobs.
*/
| > | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
** pBig in order to cause p to be nul-terminated. If pBig
** should not be modified, then use blob_str() instead of this
** routine. blob_str() will make a copy of the p if necessary
** to avoid modifying pBig.
*/
char *blob_terminate(Blob *p){
blob_is_init(p);
if( p->nUsed==0 ) return "";
p->aData[p->nUsed] = 0;
return p->aData;
}
/*
** Compare two blobs.
*/
|
| ︙ | ︙ |
Changes to src/checkin.c.
| ︙ | ︙ | |||
325 326 327 328 329 330 331 332 333 334 335 336 337 338 |
Stmt q;
Stmt q2;
char *zUuid, *zDate;
int noSign = 0; /* True to omit signing the manifest using GPG */
int isAMerge = 0; /* True if checking in a merge */
int forceFlag = 0; /* Force a fork */
char *zManifestFile; /* Name of the manifest file */
Blob manifest;
Blob muuid; /* Manifest uuid */
Blob mcksum; /* Self-checksum on the manifest */
Blob cksum1, cksum2; /* Before and after commit checksums */
Blob cksum1b; /* Checksum recorded in the manifest */
noSign = find_option("nosign","",0)!=0;
| > > | 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 |
Stmt q;
Stmt q2;
char *zUuid, *zDate;
int noSign = 0; /* True to omit signing the manifest using GPG */
int isAMerge = 0; /* True if checking in a merge */
int forceFlag = 0; /* Force a fork */
char *zManifestFile; /* Name of the manifest file */
int nBasename; /* Length of "g.zLocalRoot/" */
Blob filename; /* complete filename */
Blob manifest;
Blob muuid; /* Manifest uuid */
Blob mcksum; /* Self-checksum on the manifest */
Blob cksum1, cksum2; /* Before and after commit checksums */
Blob cksum1b; /* Checksum recorded in the manifest */
noSign = find_option("nosign","",0)!=0;
|
| ︙ | ︙ | |||
445 446 447 448 449 450 451 452 453 454 |
zDate = db_text(0, "SELECT datetime('now')");
zDate[10] = 'T';
blob_appendf(&manifest, "D %s\n", zDate);
db_prepare(&q,
"SELECT pathname, uuid FROM vfile JOIN blob ON vfile.mrid=blob.rid"
" WHERE NOT deleted AND vfile.vid=%d"
" ORDER BY 1", vid);
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
const char *zUuid = db_column_text(&q, 1);
| > > > > > > > > > > > | > | 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 |
zDate = db_text(0, "SELECT datetime('now')");
zDate[10] = 'T';
blob_appendf(&manifest, "D %s\n", zDate);
db_prepare(&q,
"SELECT pathname, uuid FROM vfile JOIN blob ON vfile.mrid=blob.rid"
" WHERE NOT deleted AND vfile.vid=%d"
" ORDER BY 1", vid);
blob_zero(&filename);
blob_appendf(&filename, "%s/", g.zLocalRoot);
nBasename = blob_size(&filename);
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
const char *zUuid = db_column_text(&q, 1);
const char *zPerm;
blob_append(&filename, zName, -1);
if( file_isexe(blob_str(&filename)) ){
zPerm = " x";
}else{
zPerm = "";
}
blob_resize(&filename, nBasename);
blob_appendf(&manifest, "F %F %s%s\n", zName, zUuid, zPerm);
}
blob_reset(&filename);
db_finalize(&q);
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
blob_appendf(&manifest, "P %s", zUuid);
db_prepare(&q2, "SELECT merge FROM vmerge WHERE id=:id");
db_bind_int(&q2, ":id", 0);
while( db_step(&q2)==SQLITE_ROW ){
|
| ︙ | ︙ |
Changes to src/checkout.c.
| ︙ | ︙ | |||
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
** Read the manifest file given by vid out of the repository
** and store it in the root of the local check-out.
*/
void manifest_to_disk(int vid){
char *zManFile;
Blob manifest;
Blob hash;
blob_zero(&manifest);
zManFile = mprintf("%smanifest", g.zLocalRoot);
content_get(vid, &manifest);
blob_write_to_file(&manifest, zManFile);
free(zManFile);
blob_zero(&hash);
sha1sum_blob(&manifest, &hash);
| > > > > < > > > > > > > > > > > > > | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
** Read the manifest file given by vid out of the repository
** and store it in the root of the local check-out.
*/
void manifest_to_disk(int vid){
char *zManFile;
Blob manifest;
Blob hash;
Blob filename;
int baseLen;
int i;
Manifest m;
blob_zero(&manifest);
zManFile = mprintf("%smanifest", g.zLocalRoot);
content_get(vid, &manifest);
blob_write_to_file(&manifest, zManFile);
free(zManFile);
blob_zero(&hash);
sha1sum_blob(&manifest, &hash);
zManFile = mprintf("%smanifest.uuid", g.zLocalRoot);
blob_append(&hash, "\n", 1);
blob_write_to_file(&hash, zManFile);
free(zManFile);
blob_reset(&hash);
manifest_parse(&m, &manifest);
blob_zero(&filename);
blob_appendf(&filename, "%s/", g.zLocalRoot);
baseLen = blob_size(&filename);
for(i=0; i<m.nFile; i++){
int isExe;
blob_append(&filename, m.aFile[i].zName, -1);
isExe = m.aFile[i].zPerm && strstr(m.aFile[i].zPerm, "x");
file_setexe(blob_str(&filename), isExe);
blob_resize(&filename, baseLen);
}
blob_reset(&filename);
manifest_clear(&m);
}
/*
** COMMAND: checkout
**
** Usage: %fossil checkout VERSION ?-f|--force?
** Check out a version specified on the command-line. This command
|
| ︙ | ︙ |
Changes to src/file.c.
| ︙ | ︙ | |||
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
int file_isfile(const char *zFilename){
struct stat buf;
if( stat(zFilename, &buf)!=0 ){
return 0;
}
return S_ISREG(buf.st_mode);
}
/*
** Return 1 if zFilename is a directory. Return 0 if zFilename
** does not exist. Return 2 if zFilename exists but is something
** other than a directory.
*/
int file_isdir(const char *zFilename){
struct stat buf;
if( stat(zFilename, &buf)!=0 ){
return 0;
}
return S_ISDIR(buf.st_mode) ? 1 : 2;
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < < < < < < < < < | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
int file_isfile(const char *zFilename){
struct stat buf;
if( stat(zFilename, &buf)!=0 ){
return 0;
}
return S_ISREG(buf.st_mode);
}
/*
** Return TRUE if the named file is an executable. Return false
** for directories, devices, fifos, symlinks, etc.
*/
int file_isexe(const char *zFilename){
struct stat buf;
if( stat(zFilename, &buf)!=0 ){
return 0;
}
return ((S_IXUSR|S_IXGRP|S_IXOTH)&buf.st_mode)!=0;
}
/*
** Set or clear the execute bit on a file.
*/
void file_setexe(const char *zFilename, int onoff){
#ifndef __MINGW32__
struct stat buf;
if( stat(zFilename, &buf)!=0 ) return;
if( onoff ){
if( (buf.st_mode & 0111)==0 ){
chmod(zFilename, buf.st_mode | 0111);
}
}else{
if( (buf.st_mode & 0111)!=0 ){
chmod(zFilename, buf.st_mode & ~0111);
}
}
#endif
}
/*
** Return 1 if zFilename is a directory. Return 0 if zFilename
** does not exist. Return 2 if zFilename exists but is something
** other than a directory.
*/
int file_isdir(const char *zFilename){
struct stat buf;
if( stat(zFilename, &buf)!=0 ){
return 0;
}
return S_ISDIR(buf.st_mode) ? 1 : 2;
}
/*
** Create the directory named in the argument, if it does not already
** exist. If forceFlag is 1, delete any prior non-directory object
** with the same name.
**
** Return the number of errors.
*/
|
| ︙ | ︙ |
Changes to src/info.c.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code to implement the "info" command. The ** "info" command gives command-line access to information about | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code to implement the "info" command. The ** "info" command gives command-line access to information about ** the current tree, or a particular artifact or baseline. */ #include "config.h" #include "info.h" #include <assert.h> /* |
| ︙ | ︙ | |||
104 105 106 107 108 109 110 |
fossil_panic("no such object: %s\n", g.argv[2]);
}
show_common_info(rid, "uuid:", 1);
}
}
/*
| | | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
fossil_panic("no such object: %s\n", g.argv[2]);
}
show_common_info(rid, "uuid:", 1);
}
}
/*
** Show information about descendents of a baseline. Do this recursively
** to a depth of N. Return true if descendents are shown and false if not.
*/
static int showDescendents(int pid, int depth, const char *zTitle){
Stmt q;
int cnt = 0;
db_prepare(&q,
"SELECT plink.cid, blob.uuid, datetime(plink.mtime, 'localtime'),"
|
| ︙ | ︙ | |||
156 157 158 159 160 161 162 |
if( cnt ){
@ </ul>
}
return cnt;
}
/*
| | | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
if( cnt ){
@ </ul>
}
return cnt;
}
/*
** Show information about ancestors of a baseline. Do this recursively
** to a depth of N. Return true if ancestors are shown and false if not.
*/
static void showAncestors(int pid, int depth, const char *zTitle){
Stmt q;
int cnt = 0;
db_prepare(&q,
"SELECT plink.pid, blob.uuid, datetime(event.mtime, 'localtime'),"
|
| ︙ | ︙ | |||
201 202 203 204 205 206 207 |
if( cnt ){
@ </ul>
}
}
/*
| | | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
if( cnt ){
@ </ul>
}
}
/*
** Show information about baselines mentioned in the "leaves" table.
*/
static void showLeaves(void){
Stmt q;
int cnt = 0;
db_prepare(&q,
"SELECT blob.uuid, datetime(event.mtime, 'localtime'),"
" coalesce(event.euser, event.user),"
|
| ︙ | ︙ | |||
238 239 240 241 242 243 244 |
@ </ul>
}
}
/*
** Show information about all tags on a given node.
*/
| | | | | 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
@ </ul>
}
}
/*
** Show information about all tags on a given node.
*/
static void showTags(int rid, const char *zNotGlob){
Stmt q;
int cnt = 0;
db_prepare(&q,
"SELECT tag.tagid, tagname, srcid, blob.uuid, value,"
" datetime(tagxref.mtime,'localtime'), tagtype"
" FROM tagxref JOIN tag ON tagxref.tagid=tag.tagid"
" LEFT JOIN blob ON blob.rid=tagxref.srcid"
" WHERE tagxref.rid=%d AND tagname NOT GLOB '%s'"
" ORDER BY tagname", rid, zNotGlob
);
while( db_step(&q)==SQLITE_ROW ){
const char *zTagname = db_column_text(&q, 1);
int srcid = db_column_int(&q, 2);
const char *zUuid = db_column_text(&q, 3);
const char *zValue = db_column_text(&q, 4);
const char *zDate = db_column_text(&q, 5);
|
| ︙ | ︙ | |||
289 290 291 292 293 294 295 | } /* ** WEBPAGE: vinfo ** URL: /vinfo?name=RID|UUID ** | | | 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
}
/*
** WEBPAGE: vinfo
** URL: /vinfo?name=RID|UUID
**
** Return information about a baseline
*/
void vinfo_page(void){
Stmt q;
int rid;
int isLeaf;
login_check_credentials();
|
| ︙ | ︙ | |||
315 316 317 318 319 320 321 |
" FROM blob, event"
" WHERE blob.rid=%d"
" AND event.objid=%d",
rid, rid
);
if( db_step(&q)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q, 0);
| | | | | | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
" FROM blob, event"
" WHERE blob.rid=%d"
" AND event.objid=%d",
rid, rid
);
if( db_step(&q)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q, 0);
char *zTitle = mprintf("Baseline [%.10s]", zUuid);
style_header(zTitle);
free(zTitle);
/*@ <h2>Version %s(zUuid)</h2>*/
@ <div class="section">Overview</div>
@ <p><table class="label-value">
@ <tr><th>Version:</th><td>%s(zUuid)</td></tr>
@ <tr><th>Date:</th><td>%s(db_column_text(&q, 1))</td></tr>
if( g.okSetup ){
@ <tr><th>Record ID:</th><td>%d(rid)</td></tr>
}
@ <tr><th>Original User:</th><td>%h(db_column_text(&q, 2))</td></tr>
@ <tr><th>Original Comment:</th><td>%w(db_column_text(&q,3))</td></tr>
@ </td></tr>
@ <tr><th>Commands:</th>
@ <td>
@ <a href="%s(g.zBaseURL)/vdiff/%d(rid)">diff</a>
@ | <a href="%s(g.zBaseURL)/zip/%s(zUuid).zip">ZIP archive</a>
@ | <a href="%s(g.zBaseURL)/artifact/%d(rid)">manifest</a>
@ </td>
@ </tr>
@ </table></p>
}else{
style_header("Baseline Information");
}
db_finalize(&q);
showTags(rid, "");
@ <div class="section">Changes</div>
@ <ul>
db_prepare(&q,
"SELECT name, pid, fid"
" FROM mlink, filename"
" WHERE mid=%d"
" AND filename.fnid=mlink.fnid",
|
| ︙ | ︙ | |||
420 421 422 423 424 425 426 |
if( g.okSetup ){
@ <tr><th>Record ID:</th><td>%d(rid)</td></tr>
}
@ <tr><th>Original User:</th><td>%s(db_column_text(&q, 3))</td></tr>
@ <tr><th>Commands:</th>
@ <td>
/* @ <a href="%s(g.zBaseURL)/wdiff/%d(rid)">diff</a> | */
| | | > | > > > > > > > > > > > > > > > > | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 |
if( g.okSetup ){
@ <tr><th>Record ID:</th><td>%d(rid)</td></tr>
}
@ <tr><th>Original User:</th><td>%s(db_column_text(&q, 3))</td></tr>
@ <tr><th>Commands:</th>
@ <td>
/* @ <a href="%s(g.zBaseURL)/wdiff/%d(rid)">diff</a> | */
@ <a href="%s(g.zBaseURL)/whistory?name=%t(zName)">history</a>
@ | <a href="%s(g.zBaseURL)/artifact/%d(rid)">raw-text</a>
@ </td>
@ </tr>
@ </table></p>
}else{
style_header("Wiki Information");
rid = 0;
}
db_finalize(&q);
showTags(rid, "wiki-*");
if( rid ){
Blob content;
Manifest m;
memset(&m, 0, sizeof(m));
blob_zero(&m.content);
content_get(rid, &content);
manifest_parse(&m, &content);
if( m.type==CFTYPE_WIKI ){
Blob wiki;
blob_init(&wiki, m.zWiki, -1);
@ <div class="section">Content</div>
wiki_convert(&wiki, 0, 0);
blob_reset(&wiki);
}
manifest_clear(&m);
}
style_footer();
}
/*
** WEBPAGE: finfo
** URL: /finfo?name=FILENAME
**
|
| ︙ | ︙ | |||
497 498 499 500 501 502 503 |
}
@ <tr><td valign="top">%s(&zDate[11])</td>
@ <td width="20"></td>
@ <td valign="top" align="left">
hyperlink_to_uuid(zVers);
@ %h(zCom) (By: %h(zUser))
@ Id: %s(zUuid)/%d(frid)
| | | 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 |
}
@ <tr><td valign="top">%s(&zDate[11])</td>
@ <td width="20"></td>
@ <td valign="top" align="left">
hyperlink_to_uuid(zVers);
@ %h(zCom) (By: %h(zUser))
@ Id: %s(zUuid)/%d(frid)
@ <a href="%s(g.zBaseURL)/artifact/%d(frid)">[view]</a>
if( fpid ){
@ <a href="%s(g.zBaseURL)/fdiff?v1=%d(fpid)&v2=%d(frid)">[diff]</a>
}
@ <a href="%s(g.zBaseURL)/annotate?mid=%d(mid)&fnid=%d(fnid)">
@ [annotate]</a>
@ </td>
}
|
| ︙ | ︙ | |||
539 540 541 542 543 544 545 |
void vdiff_page(void){
int rid;
Stmt q;
char *zUuid;
login_check_credentials();
if( !g.okHistory ){ login_needed(); return; }
| | | | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 |
void vdiff_page(void){
int rid;
Stmt q;
char *zUuid;
login_check_credentials();
if( !g.okHistory ){ login_needed(); return; }
style_header("Baseline Changes");
rid = name_to_rid(PD("name",""));
if( rid==0 ){
cgi_redirect("index");
}
db_prepare(&q,
"SELECT pid, fid, name"
" FROM mlink, filename"
" WHERE mlink.mid=%d"
" AND filename.fnid=mlink.fnid"
" ORDER BY name",
rid
);
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
@ <h2>All Changes In Baseline
hyperlink_to_uuid(zUuid);
@ </h2>
while( db_step(&q)==SQLITE_ROW ){
int pid = db_column_int(&q,0);
int fid = db_column_int(&q,1);
const char *zName = db_column_text(&q,2);
@ <p><a href="%s(g.zBaseURL)/finfo?name=%T(zName)">%h(zName)</a></p>
|
| ︙ | ︙ | |||
578 579 580 581 582 583 584 | /* ** Write a description of an object to the www reply. ** ** If the object is a file then mention: ** ** * It's uuid ** * All its filenames | | | 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 | /* ** Write a description of an object to the www reply. ** ** If the object is a file then mention: ** ** * It's uuid ** * All its filenames ** * The baselines it was checked-in on, with times and users ** ** If the object is a manifest, then mention: ** ** * It's uuid ** * date of check-in ** * Comment & user */ |
| ︙ | ︙ | |||
642 643 644 645 646 647 648 |
@ uuid %s(zUuid) by %h(zUser) on %s(zDate)
nWiki++;
cnt++;
}
db_finalize(&q);
if( nWiki==0 ){
db_prepare(&q,
| | > > > > > > | > > > | | 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 |
@ uuid %s(zUuid) by %h(zUser) on %s(zDate)
nWiki++;
cnt++;
}
db_finalize(&q);
if( nWiki==0 ){
db_prepare(&q,
"SELECT datetime(mtime), user, comment, uuid, type"
" FROM event, blob"
" WHERE event.objid=%d"
" AND blob.rid=%d",
rid, rid
);
while( db_step(&q)==SQLITE_ROW ){
const char *zDate = db_column_text(&q, 0);
const char *zUuid = db_column_text(&q, 3);
const char *zUser = db_column_text(&q, 1);
const char *zCom = db_column_text(&q, 2);
const char *zType = db_column_text(&q, 4);
if( zType[0]=='w' ){
@ Wiki edit
}else if( zType[0]=='t' ){
@ Ticket change
}else if( zType[0]=='c' ){
@ Manifest of baseline
}else{
@ Control file referencing
}
hyperlink_to_uuid(zUuid);
@ %w(zCom) by %h(zUser) on %s(zDate)
cnt++;
}
db_finalize(&q);
}
if( cnt==0 ){
char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
@ Control file %s(zUuid).
}else if( linkToView ){
@ <a href="%s(g.zBaseURL)/artifact/%d(rid)">[view]</a>
}
}
/*
** WEBPAGE: fdiff
**
** Two arguments, v1 and v2, are integers. Show the difference between
|
| ︙ | ︙ | |||
705 706 707 708 709 710 711 | @ %h(blob_str(&diff)) @ </pre></blockquote> blob_reset(&diff); style_footer(); } /* | | | | | | > | < | < < < < | < < < < < < < < | | < < < < < < | < < | < | | | > | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 |
@ %h(blob_str(&diff))
@ </pre></blockquote>
blob_reset(&diff);
style_footer();
}
/*
** WEBPAGE: artifact
** URL: /artifact?name=UUID
**
** Show the complete content of a file identified by UUID
** as preformatted text.
*/
void artifact_page(void){
int rid;
Blob content;
rid = name_to_rid(PD("name","0"));
login_check_credentials();
if( !g.okHistory ){ login_needed(); return; }
if( g.zPath[0]=='i' ){
if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)"
" WHERE rid=%d AND tagname LIKE 'wiki-%%'", rid) ){
winfo_page();
return;
}
if( db_exists("SELECT 1 FROM plink WHERE cid=%d", rid) ){
vinfo_page();
return;
}
}
style_header("Artifact Content");
@ <h2>Content Of:</h2>
@ <blockquote>
object_description(rid, 0);
@ </blockquote>
@ <hr>
@ <blockquote><pre>
content_get(rid, &content);
@ %h(blob_str(&content))
@ </pre></blockquote>
blob_reset(&content);
style_footer();
}
/*
** WEBPAGE: info
** URL: info/UUID
**
** The argument is a UUID which might be a baseline or a file or
** a ticket changes or a wiki editor or something else.
**
** Figure out what the UUID is and jump to it.
*/
void info_page(void){
const char *zName;
int rid, nName;
zName = P("name");
if( zName==0 ) cgi_redirect("index");
nName = strlen(zName);
if( nName<4 || nName>UUID_SIZE || !validate16(zName, nName) ){
cgi_redirect("index");
}
rid = db_int(0, "SELECT rid FROM blob WHERE uuid GLOB '%s*'");
if( rid==0 ){
style_header("Broken Link");
@ <p>No such object: %h(zName)</p>
style_footer();
return;
}
if( db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){
vinfo_page();
}else
if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
finfo_page();
}else
{
artifact_page();
}
}
|
Changes to src/main.c.
| ︙ | ︙ | |||
63 64 65 66 67 68 69 70 71 72 73 74 75 76 | char *zBaseURL; /* Full text of the URL being served */ char *zTop; /* Parent directory of zPath */ const char *zContentType; /* The content type of the input HTTP request */ int iErrPriority; /* Priority of current error message */ char *zErrMsg; /* Text of an error message */ Blob cgiIn; /* Input to an xfer www method */ int cgiPanic; /* Write error messages to CGI */ int *aCommitFile; int urlIsFile; /* True if a "file:" url */ char *urlName; /* Hostname for http: or filename for file: */ int urlPort; /* TCP port number for http: */ char *urlPath; /* Pathname for http: */ | > | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | char *zBaseURL; /* Full text of the URL being served */ char *zTop; /* Parent directory of zPath */ const char *zContentType; /* The content type of the input HTTP request */ int iErrPriority; /* Priority of current error message */ char *zErrMsg; /* Text of an error message */ Blob cgiIn; /* Input to an xfer www method */ int cgiPanic; /* Write error messages to CGI */ Th_Interp *interp; /* The TH1 interpreter */ int *aCommitFile; int urlIsFile; /* True if a "file:" url */ char *urlName; /* Hostname for http: or filename for file: */ int urlPort; /* TCP port number for http: */ char *urlPath; /* Pathname for http: */ |
| ︙ | ︙ |
Changes to src/main.mk.
| ︙ | ︙ | |||
50 51 52 53 54 55 56 | $(SRCDIR)/printf.c \ $(SRCDIR)/rebuild.c \ $(SRCDIR)/rss.c \ $(SRCDIR)/schema.c \ $(SRCDIR)/setup.c \ $(SRCDIR)/sha1.c \ $(SRCDIR)/style.c \ | < > | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | $(SRCDIR)/printf.c \ $(SRCDIR)/rebuild.c \ $(SRCDIR)/rss.c \ $(SRCDIR)/schema.c \ $(SRCDIR)/setup.c \ $(SRCDIR)/sha1.c \ $(SRCDIR)/style.c \ $(SRCDIR)/sync.c \ $(SRCDIR)/tag.c \ $(SRCDIR)/tagview.c \ $(SRCDIR)/th_main.c \ $(SRCDIR)/timeline.c \ $(SRCDIR)/tkt.c \ $(SRCDIR)/tktconfig.c \ $(SRCDIR)/tktsetup.c \ $(SRCDIR)/undo.c \ $(SRCDIR)/update.c \ $(SRCDIR)/url.c \ |
| ︙ | ︙ | |||
111 112 113 114 115 116 117 | printf_.c \ rebuild_.c \ rss_.c \ schema_.c \ setup_.c \ sha1_.c \ style_.c \ | < > | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | printf_.c \ rebuild_.c \ rss_.c \ schema_.c \ setup_.c \ sha1_.c \ style_.c \ sync_.c \ tag_.c \ tagview_.c \ th_main_.c \ timeline_.c \ tkt_.c \ tktconfig_.c \ tktsetup_.c \ undo_.c \ update_.c \ url_.c \ |
| ︙ | ︙ | |||
172 173 174 175 176 177 178 | printf.o \ rebuild.o \ rss.o \ schema.o \ setup.o \ sha1.o \ style.o \ | < > | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | printf.o \ rebuild.o \ rss.o \ schema.o \ setup.o \ sha1.o \ style.o \ sync.o \ tag.o \ tagview.o \ th_main.o \ timeline.o \ tkt.o \ tktconfig.o \ tktsetup.o \ undo.o \ update.o \ url.o \ |
| ︙ | ︙ | |||
220 221 222 223 224 225 226 |
$(TCLSH) test/tester.tcl $(APPNAME)
VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest
awk '{ printf "#define MANIFEST_UUID \"%s\"\n", $$1}' $(SRCDIR)/../manifest.uuid >VERSION.h
awk '{ printf "#define MANIFEST_VERSION \"[%.10s]\"\n", $$1}' $(SRCDIR)/../manifest.uuid >>VERSION.h
awk '$$1=="D"{printf "#define MANIFEST_DATE \"%s %s\"\n", substr($$2,1,10),substr($$2,12)}' $(SRCDIR)/../manifest >>VERSION.h
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < < < < < < < | | | > > > > > > > > > > | | | | | | | | | | | | | | > > > > > > | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 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 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 |
$(TCLSH) test/tester.tcl $(APPNAME)
VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest
awk '{ printf "#define MANIFEST_UUID \"%s\"\n", $$1}' $(SRCDIR)/../manifest.uuid >VERSION.h
awk '{ printf "#define MANIFEST_VERSION \"[%.10s]\"\n", $$1}' $(SRCDIR)/../manifest.uuid >>VERSION.h
awk '$$1=="D"{printf "#define MANIFEST_DATE \"%s %s\"\n", substr($$2,1,10),substr($$2,12)}' $(SRCDIR)/../manifest >>VERSION.h
$(APPNAME): headers $(OBJ) sqlite3.o th.o th_lang.o
$(TCC) -o $(APPNAME) $(OBJ) sqlite3.o th.o th_lang.o $(LIB)
# This rule prevents make from using its default rules to try build
# an executable named "manifest" out of the file named "manifest.c"
#
$(SRCDIR)/../manifest:
# noop
clean:
rm -f *.o *_.c $(APPNAME) VERSION.h
rm -f translate makeheaders mkindex page_index.h headers
rm -f add.h admin.h bag.h blob.h branch.h browse.h cgi.h checkin.h checkout.h clearsign.h clone.h comformat.h construct.h content.h db.h delta.h deltacmd.h descendents.h diff.h diffcmd.h encode.h file.h http.h info.h login.h main.h manifest.h md5.h merge.h merge3.h my_page.h name.h pivot.h pqueue.h printf.h rebuild.h rss.h schema.h setup.h sha1.h style.h sync.h tag.h tagview.h th_main.h timeline.h tkt.h tktconfig.h tktsetup.h undo.h update.h url.h user.h verify.h vfile.h wiki.h wikiformat.h xfer.h zip.h
headers: makeheaders mkindex $(TRANS_SRC) ./VERSION.h
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
./mkindex $(TRANS_SRC) >page_index.h
touch headers
add_.c: $(SRCDIR)/add.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/add.c | sed -f $(SRCDIR)/VERSION >add_.c
add.o: add_.c add.h $(SRCDIR)/config.h
$(XTCC) -o add.o -c add_.c
add.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
admin_.c: $(SRCDIR)/admin.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/admin.c | sed -f $(SRCDIR)/VERSION >admin_.c
admin.o: admin_.c admin.h $(SRCDIR)/config.h
$(XTCC) -o admin.o -c admin_.c
admin.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
bag_.c: $(SRCDIR)/bag.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/bag.c | sed -f $(SRCDIR)/VERSION >bag_.c
bag.o: bag_.c bag.h $(SRCDIR)/config.h
$(XTCC) -o bag.o -c bag_.c
bag.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
blob_.c: $(SRCDIR)/blob.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/blob.c | sed -f $(SRCDIR)/VERSION >blob_.c
blob.o: blob_.c blob.h $(SRCDIR)/config.h
$(XTCC) -o blob.o -c blob_.c
blob.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
branch_.c: $(SRCDIR)/branch.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/branch.c | sed -f $(SRCDIR)/VERSION >branch_.c
branch.o: branch_.c branch.h $(SRCDIR)/config.h
$(XTCC) -o branch.o -c branch_.c
branch.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
browse_.c: $(SRCDIR)/browse.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/browse.c | sed -f $(SRCDIR)/VERSION >browse_.c
browse.o: browse_.c browse.h $(SRCDIR)/config.h
$(XTCC) -o browse.o -c browse_.c
browse.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
cgi_.c: $(SRCDIR)/cgi.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/cgi.c | sed -f $(SRCDIR)/VERSION >cgi_.c
cgi.o: cgi_.c cgi.h $(SRCDIR)/config.h
$(XTCC) -o cgi.o -c cgi_.c
cgi.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
checkin_.c: $(SRCDIR)/checkin.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/checkin.c | sed -f $(SRCDIR)/VERSION >checkin_.c
checkin.o: checkin_.c checkin.h $(SRCDIR)/config.h
$(XTCC) -o checkin.o -c checkin_.c
checkin.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
checkout_.c: $(SRCDIR)/checkout.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/checkout.c | sed -f $(SRCDIR)/VERSION >checkout_.c
checkout.o: checkout_.c checkout.h $(SRCDIR)/config.h
$(XTCC) -o checkout.o -c checkout_.c
checkout.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
clearsign_.c: $(SRCDIR)/clearsign.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/clearsign.c | sed -f $(SRCDIR)/VERSION >clearsign_.c
clearsign.o: clearsign_.c clearsign.h $(SRCDIR)/config.h
$(XTCC) -o clearsign.o -c clearsign_.c
clearsign.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
clone_.c: $(SRCDIR)/clone.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/clone.c | sed -f $(SRCDIR)/VERSION >clone_.c
clone.o: clone_.c clone.h $(SRCDIR)/config.h
$(XTCC) -o clone.o -c clone_.c
clone.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
comformat_.c: $(SRCDIR)/comformat.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/comformat.c | sed -f $(SRCDIR)/VERSION >comformat_.c
comformat.o: comformat_.c comformat.h $(SRCDIR)/config.h
$(XTCC) -o comformat.o -c comformat_.c
comformat.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
construct_.c: $(SRCDIR)/construct.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/construct.c | sed -f $(SRCDIR)/VERSION >construct_.c
construct.o: construct_.c construct.h $(SRCDIR)/config.h
$(XTCC) -o construct.o -c construct_.c
construct.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
content_.c: $(SRCDIR)/content.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/content.c | sed -f $(SRCDIR)/VERSION >content_.c
content.o: content_.c content.h $(SRCDIR)/config.h
$(XTCC) -o content.o -c content_.c
content.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
db_.c: $(SRCDIR)/db.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/db.c | sed -f $(SRCDIR)/VERSION >db_.c
db.o: db_.c db.h $(SRCDIR)/config.h
$(XTCC) -o db.o -c db_.c
db.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
delta_.c: $(SRCDIR)/delta.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/delta.c | sed -f $(SRCDIR)/VERSION >delta_.c
delta.o: delta_.c delta.h $(SRCDIR)/config.h
$(XTCC) -o delta.o -c delta_.c
delta.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
deltacmd_.c: $(SRCDIR)/deltacmd.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/deltacmd.c | sed -f $(SRCDIR)/VERSION >deltacmd_.c
deltacmd.o: deltacmd_.c deltacmd.h $(SRCDIR)/config.h
$(XTCC) -o deltacmd.o -c deltacmd_.c
deltacmd.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
descendents_.c: $(SRCDIR)/descendents.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/descendents.c | sed -f $(SRCDIR)/VERSION >descendents_.c
descendents.o: descendents_.c descendents.h $(SRCDIR)/config.h
$(XTCC) -o descendents.o -c descendents_.c
descendents.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
diff_.c: $(SRCDIR)/diff.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/diff.c | sed -f $(SRCDIR)/VERSION >diff_.c
diff.o: diff_.c diff.h $(SRCDIR)/config.h
$(XTCC) -o diff.o -c diff_.c
diff.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
diffcmd_.c: $(SRCDIR)/diffcmd.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/diffcmd.c | sed -f $(SRCDIR)/VERSION >diffcmd_.c
diffcmd.o: diffcmd_.c diffcmd.h $(SRCDIR)/config.h
$(XTCC) -o diffcmd.o -c diffcmd_.c
diffcmd.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
encode_.c: $(SRCDIR)/encode.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/encode.c | sed -f $(SRCDIR)/VERSION >encode_.c
encode.o: encode_.c encode.h $(SRCDIR)/config.h
$(XTCC) -o encode.o -c encode_.c
encode.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
file_.c: $(SRCDIR)/file.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/file.c | sed -f $(SRCDIR)/VERSION >file_.c
file.o: file_.c file.h $(SRCDIR)/config.h
$(XTCC) -o file.o -c file_.c
file.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
http_.c: $(SRCDIR)/http.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/http.c | sed -f $(SRCDIR)/VERSION >http_.c
http.o: http_.c http.h $(SRCDIR)/config.h
$(XTCC) -o http.o -c http_.c
http.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
info_.c: $(SRCDIR)/info.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/info.c | sed -f $(SRCDIR)/VERSION >info_.c
info.o: info_.c info.h $(SRCDIR)/config.h
$(XTCC) -o info.o -c info_.c
info.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
login_.c: $(SRCDIR)/login.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/login.c | sed -f $(SRCDIR)/VERSION >login_.c
login.o: login_.c login.h $(SRCDIR)/config.h
$(XTCC) -o login.o -c login_.c
login.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
main_.c: $(SRCDIR)/main.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/main.c | sed -f $(SRCDIR)/VERSION >main_.c
main.o: main_.c main.h page_index.h $(SRCDIR)/config.h
$(XTCC) -o main.o -c main_.c
main.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
manifest_.c: $(SRCDIR)/manifest.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/manifest.c | sed -f $(SRCDIR)/VERSION >manifest_.c
manifest.o: manifest_.c manifest.h $(SRCDIR)/config.h
$(XTCC) -o manifest.o -c manifest_.c
manifest.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
md5_.c: $(SRCDIR)/md5.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/md5.c | sed -f $(SRCDIR)/VERSION >md5_.c
md5.o: md5_.c md5.h $(SRCDIR)/config.h
$(XTCC) -o md5.o -c md5_.c
md5.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
merge_.c: $(SRCDIR)/merge.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/merge.c | sed -f $(SRCDIR)/VERSION >merge_.c
merge.o: merge_.c merge.h $(SRCDIR)/config.h
$(XTCC) -o merge.o -c merge_.c
merge.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
merge3_.c: $(SRCDIR)/merge3.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/merge3.c | sed -f $(SRCDIR)/VERSION >merge3_.c
merge3.o: merge3_.c merge3.h $(SRCDIR)/config.h
$(XTCC) -o merge3.o -c merge3_.c
merge3.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
my_page_.c: $(SRCDIR)/my_page.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/my_page.c | sed -f $(SRCDIR)/VERSION >my_page_.c
my_page.o: my_page_.c my_page.h $(SRCDIR)/config.h
$(XTCC) -o my_page.o -c my_page_.c
my_page.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
name_.c: $(SRCDIR)/name.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/name.c | sed -f $(SRCDIR)/VERSION >name_.c
name.o: name_.c name.h $(SRCDIR)/config.h
$(XTCC) -o name.o -c name_.c
name.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
pivot_.c: $(SRCDIR)/pivot.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/pivot.c | sed -f $(SRCDIR)/VERSION >pivot_.c
pivot.o: pivot_.c pivot.h $(SRCDIR)/config.h
$(XTCC) -o pivot.o -c pivot_.c
pivot.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
pqueue_.c: $(SRCDIR)/pqueue.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/pqueue.c | sed -f $(SRCDIR)/VERSION >pqueue_.c
pqueue.o: pqueue_.c pqueue.h $(SRCDIR)/config.h
$(XTCC) -o pqueue.o -c pqueue_.c
pqueue.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
printf_.c: $(SRCDIR)/printf.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/printf.c | sed -f $(SRCDIR)/VERSION >printf_.c
printf.o: printf_.c printf.h $(SRCDIR)/config.h
$(XTCC) -o printf.o -c printf_.c
printf.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
rebuild_.c: $(SRCDIR)/rebuild.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/rebuild.c | sed -f $(SRCDIR)/VERSION >rebuild_.c
rebuild.o: rebuild_.c rebuild.h $(SRCDIR)/config.h
$(XTCC) -o rebuild.o -c rebuild_.c
rebuild.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
rss_.c: $(SRCDIR)/rss.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/rss.c | sed -f $(SRCDIR)/VERSION >rss_.c
rss.o: rss_.c rss.h $(SRCDIR)/config.h
$(XTCC) -o rss.o -c rss_.c
rss.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
schema_.c: $(SRCDIR)/schema.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/schema.c | sed -f $(SRCDIR)/VERSION >schema_.c
schema.o: schema_.c schema.h $(SRCDIR)/config.h
$(XTCC) -o schema.o -c schema_.c
schema.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
setup_.c: $(SRCDIR)/setup.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/setup.c | sed -f $(SRCDIR)/VERSION >setup_.c
setup.o: setup_.c setup.h $(SRCDIR)/config.h
$(XTCC) -o setup.o -c setup_.c
setup.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
sha1_.c: $(SRCDIR)/sha1.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/sha1.c | sed -f $(SRCDIR)/VERSION >sha1_.c
sha1.o: sha1_.c sha1.h $(SRCDIR)/config.h
$(XTCC) -o sha1.o -c sha1_.c
sha1.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
style_.c: $(SRCDIR)/style.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/style.c | sed -f $(SRCDIR)/VERSION >style_.c
style.o: style_.c style.h $(SRCDIR)/config.h
$(XTCC) -o style.o -c style_.c
style.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
sync_.c: $(SRCDIR)/sync.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/sync.c | sed -f $(SRCDIR)/VERSION >sync_.c
sync.o: sync_.c sync.h $(SRCDIR)/config.h
$(XTCC) -o sync.o -c sync_.c
sync.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
tag_.c: $(SRCDIR)/tag.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/tag.c | sed -f $(SRCDIR)/VERSION >tag_.c
tag.o: tag_.c tag.h $(SRCDIR)/config.h
$(XTCC) -o tag.o -c tag_.c
tag.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
tagview_.c: $(SRCDIR)/tagview.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/tagview.c | sed -f $(SRCDIR)/VERSION >tagview_.c
tagview.o: tagview_.c tagview.h $(SRCDIR)/config.h
$(XTCC) -o tagview.o -c tagview_.c
tagview.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
th_main_.c: $(SRCDIR)/th_main.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/th_main.c | sed -f $(SRCDIR)/VERSION >th_main_.c
th_main.o: th_main_.c th_main.h $(SRCDIR)/config.h
$(XTCC) -o th_main.o -c th_main_.c
th_main.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
timeline_.c: $(SRCDIR)/timeline.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/timeline.c | sed -f $(SRCDIR)/VERSION >timeline_.c
timeline.o: timeline_.c timeline.h $(SRCDIR)/config.h
$(XTCC) -o timeline.o -c timeline_.c
timeline.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
tkt_.c: $(SRCDIR)/tkt.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/tkt.c | sed -f $(SRCDIR)/VERSION >tkt_.c
tkt.o: tkt_.c tkt.h $(SRCDIR)/config.h
$(XTCC) -o tkt.o -c tkt_.c
tkt.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
tktconfig_.c: $(SRCDIR)/tktconfig.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/tktconfig.c | sed -f $(SRCDIR)/VERSION >tktconfig_.c
tktconfig.o: tktconfig_.c tktconfig.h $(SRCDIR)/config.h
$(XTCC) -o tktconfig.o -c tktconfig_.c
tktconfig.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
tktsetup_.c: $(SRCDIR)/tktsetup.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/tktsetup.c | sed -f $(SRCDIR)/VERSION >tktsetup_.c
tktsetup.o: tktsetup_.c tktsetup.h $(SRCDIR)/config.h
$(XTCC) -o tktsetup.o -c tktsetup_.c
tktsetup.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
undo_.c: $(SRCDIR)/undo.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/undo.c | sed -f $(SRCDIR)/VERSION >undo_.c
undo.o: undo_.c undo.h $(SRCDIR)/config.h
$(XTCC) -o undo.o -c undo_.c
undo.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
update_.c: $(SRCDIR)/update.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/update.c | sed -f $(SRCDIR)/VERSION >update_.c
update.o: update_.c update.h $(SRCDIR)/config.h
$(XTCC) -o update.o -c update_.c
update.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
url_.c: $(SRCDIR)/url.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/url.c | sed -f $(SRCDIR)/VERSION >url_.c
url.o: url_.c url.h $(SRCDIR)/config.h
$(XTCC) -o url.o -c url_.c
url.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
user_.c: $(SRCDIR)/user.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/user.c | sed -f $(SRCDIR)/VERSION >user_.c
user.o: user_.c user.h $(SRCDIR)/config.h
$(XTCC) -o user.o -c user_.c
user.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
verify_.c: $(SRCDIR)/verify.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/verify.c | sed -f $(SRCDIR)/VERSION >verify_.c
verify.o: verify_.c verify.h $(SRCDIR)/config.h
$(XTCC) -o verify.o -c verify_.c
verify.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
vfile_.c: $(SRCDIR)/vfile.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/vfile.c | sed -f $(SRCDIR)/VERSION >vfile_.c
vfile.o: vfile_.c vfile.h $(SRCDIR)/config.h
$(XTCC) -o vfile.o -c vfile_.c
vfile.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
wiki_.c: $(SRCDIR)/wiki.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/wiki.c | sed -f $(SRCDIR)/VERSION >wiki_.c
wiki.o: wiki_.c wiki.h $(SRCDIR)/config.h
$(XTCC) -o wiki.o -c wiki_.c
wiki.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
wikiformat_.c: $(SRCDIR)/wikiformat.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/wikiformat.c | sed -f $(SRCDIR)/VERSION >wikiformat_.c
wikiformat.o: wikiformat_.c wikiformat.h $(SRCDIR)/config.h
$(XTCC) -o wikiformat.o -c wikiformat_.c
wikiformat.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
xfer_.c: $(SRCDIR)/xfer.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/xfer.c | sed -f $(SRCDIR)/VERSION >xfer_.c
xfer.o: xfer_.c xfer.h $(SRCDIR)/config.h
$(XTCC) -o xfer.o -c xfer_.c
xfer.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
zip_.c: $(SRCDIR)/zip.c $(SRCDIR)/VERSION translate
./translate $(SRCDIR)/zip.c | sed -f $(SRCDIR)/VERSION >zip_.c
zip.o: zip_.c zip.h $(SRCDIR)/config.h
$(XTCC) -o zip.o -c zip_.c
zip.h: makeheaders
./makeheaders add_.c:add.h admin_.c:admin.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendents_.c:descendents.h diff_.c:diff.h diffcmd_.c:diffcmd.h encode_.c:encode.h file_.c:file.h http_.c:http.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h rss_.c:rss.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktconfig_.c:tktconfig.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h ./VERSION.h
touch headers
sqlite3.o: $(SRCDIR)/sqlite3.c
$(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_PRIVATE= -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_FTS3=1 -c $(SRCDIR)/sqlite3.c -o sqlite3.o
th.o: $(SRCDIR)/th.c
$(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th.c -o th.o
th_lang.o: $(SRCDIR)/th_lang.c
$(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th_lang.c -o th_lang.o
|
Changes to src/makemake.tcl.
1 2 3 4 5 | #!/usr/bin/tclsh # # Run this TCL script to generate the "main.mk" makefile. # | | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!/usr/bin/tclsh
#
# Run this TCL script to generate the "main.mk" makefile.
#
# Basenames of all source files that get preprocessed using
# "translate" and "makeheaders"
#
set src {
add
admin
bag
blob
branch
|
| ︙ | ︙ | |||
43 44 45 46 47 48 49 | printf rebuild rss schema setup sha1 style | < > | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | printf rebuild rss schema setup sha1 style sync tag tagview th_main timeline tkt tktconfig tktsetup undo update url |
| ︙ | ︙ | |||
129 130 131 132 133 134 135 |
$(SRCDIR)/../manifest.uuid >VERSION.h
awk '{ printf "#define MANIFEST_VERSION \"[%.10s]\"\n", $$1}' \
$(SRCDIR)/../manifest.uuid >>VERSION.h
awk '$$1=="D"{printf "#define MANIFEST_DATE \"%s %s\"\n",\
substr($$2,1,10),substr($$2,12)}' \
$(SRCDIR)/../manifest >>VERSION.h
| | | | > > | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
$(SRCDIR)/../manifest.uuid >VERSION.h
awk '{ printf "#define MANIFEST_VERSION \"[%.10s]\"\n", $$1}' \
$(SRCDIR)/../manifest.uuid >>VERSION.h
awk '$$1=="D"{printf "#define MANIFEST_DATE \"%s %s\"\n",\
substr($$2,1,10),substr($$2,12)}' \
$(SRCDIR)/../manifest >>VERSION.h
$(APPNAME): headers $(OBJ) sqlite3.o th.o th_lang.o
$(TCC) -o $(APPNAME) $(OBJ) sqlite3.o th.o th_lang.o $(LIB)
# This rule prevents make from using its default rules to try build
# an executable named "manifest" out of the file named "manifest.c"
#
$(SRCDIR)/../manifest:
# noop
clean:
rm -f *.o *_.c $(APPNAME) VERSION.h
rm -f translate makeheaders mkindex page_index.h headers}
set hfiles {}
foreach s [lsort $src] {lappend hfiles $s.h}
puts "\trm -f $hfiles\n"
set mhargs {}
foreach s [lsort $src] {
append mhargs " ${s}_.c:$s.h"
set extra_h($s) {}
}
append mhargs " \$(SRCDIR)/sqlite3.h"
append mhargs " \$(SRCDIR)/th.h"
append mhargs " ./VERSION.h"
puts "headers:\tmakeheaders mkindex \$(TRANS_SRC) ./VERSION.h"
puts "\t./makeheaders $mhargs"
puts "\t./mkindex \$(TRANS_SRC) >page_index.h"
puts "\ttouch headers\n"
set extra_h(main) page_index.h
foreach s [lsort $src] {
|
| ︙ | ︙ | |||
173 174 175 176 177 178 179 |
puts "sqlite3.o:\t\$(SRCDIR)/sqlite3.c"
set opt {-DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_PRIVATE=}
append opt " -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4"
append opt " -DSQLITE_ENABLE_FTS3=1"
puts "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o sqlite3.o\n"
| > > > > > > | 176 177 178 179 180 181 182 183 184 185 186 187 188 |
puts "sqlite3.o:\t\$(SRCDIR)/sqlite3.c"
set opt {-DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_PRIVATE=}
append opt " -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4"
append opt " -DSQLITE_ENABLE_FTS3=1"
puts "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o sqlite3.o\n"
puts "th.o:\t\$(SRCDIR)/th.c"
puts "\t\$(XTCC) -I\$(SRCDIR) -c \$(SRCDIR)/th.c -o th.o\n"
puts "th_lang.o:\t\$(SRCDIR)/th_lang.c"
puts "\t\$(XTCC) -I\$(SRCDIR) -c \$(SRCDIR)/th_lang.c -o th_lang.o\n"
|
Changes to src/manifest.c.
| ︙ | ︙ | |||
63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
char *zWikiTitle; /* Name of the wiki page */
char *zTicketUuid; /* UUID for a ticket */
int nFile; /* Number of F lines */
int nFileAlloc; /* Slots allocated in aFile[] */
struct {
char *zName; /* Name of a file */
char *zUuid; /* UUID of the file */
} *aFile;
int nParent; /* Number of parents */
int nParentAlloc; /* Slots allocated in azParent[] */
char **azParent; /* UUIDs of parents */
int nCChild; /* Number of cluster children */
int nCChildAlloc; /* Number of closts allocated in azCChild[] */
char **azCChild; /* UUIDs of referenced objects in a cluster */
| > | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
char *zWikiTitle; /* Name of the wiki page */
char *zTicketUuid; /* UUID for a ticket */
int nFile; /* Number of F lines */
int nFileAlloc; /* Slots allocated in aFile[] */
struct {
char *zName; /* Name of a file */
char *zUuid; /* UUID of the file */
char *zPerm; /* File permissions */
} *aFile;
int nParent; /* Number of parents */
int nParentAlloc; /* Slots allocated in azParent[] */
char **azParent; /* UUIDs of parents */
int nCChild; /* Number of cluster children */
int nCChildAlloc; /* Number of closts allocated in azCChild[] */
char **azCChild; /* UUIDs of referenced objects in a cluster */
|
| ︙ | ︙ | |||
153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
memcpy(p->zUuid, blob_buffer(&selfuuid), UUID_SIZE);
p->zUuid[UUID_SIZE] = 0;
blob_zero(pContent);
pContent = &p->content;
blob_zero(&a1);
blob_zero(&a2);
md5sum_init();
while( blob_line(pContent, &line) ){
char *z = blob_buffer(&line);
lineNo++;
if( z[0]=='-' ){
if( strncmp(z, "-----BEGIN PGP ", 15)!=0 ){
goto manifest_syntax_error;
| > | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
memcpy(p->zUuid, blob_buffer(&selfuuid), UUID_SIZE);
p->zUuid[UUID_SIZE] = 0;
blob_zero(pContent);
pContent = &p->content;
blob_zero(&a1);
blob_zero(&a2);
blob_zero(&a3);
md5sum_init();
while( blob_line(pContent, &line) ){
char *z = blob_buffer(&line);
lineNo++;
if( z[0]=='-' ){
if( strncmp(z, "-----BEGIN PGP ", 15)!=0 ){
goto manifest_syntax_error;
|
| ︙ | ︙ | |||
273 274 275 276 277 278 279 |
}else{
goto manifest_syntax_error;
}
break;
}
/*
| | | < > > > | 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
}else{
goto manifest_syntax_error;
}
break;
}
/*
** F <filename> <uuid> ?<permissions>?
**
** Identifies a file in a manifest. Multiple F lines are
** allowed in a manifest. F lines are not allowed in any
** other control file. The filename is fossil-encoded.
*/
case 'F': {
char *zName, *zUuid, *zPerm;
md5sum_step_text(blob_buffer(&line), blob_size(&line));
if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
if( blob_token(&line, &a2)==0 ) goto manifest_syntax_error;
zName = blob_terminate(&a1);
zUuid = blob_terminate(&a2);
blob_token(&line, &a3);
zPerm = blob_terminate(&a3);
if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error;
if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error;
defossilize(zName);
if( !file_is_simple_pathname(zName) ){
goto manifest_syntax_error;
}
if( p->nFile>=p->nFileAlloc ){
p->nFileAlloc = p->nFileAlloc*2 + 10;
p->aFile = realloc(p->aFile, p->nFileAlloc*sizeof(p->aFile[0]) );
if( p->aFile==0 ) fossil_panic("out of memory");
}
i = p->nFile++;
p->aFile[i].zName = zName;
p->aFile[i].zUuid = zUuid;
p->aFile[i].zPerm = zPerm;
if( i>0 && strcmp(p->aFile[i-1].zName, zName)>=0 ){
goto manifest_syntax_error;
}
break;
}
/*
|
| ︙ | ︙ |
Changes to src/schema.c.
| ︙ | ︙ | |||
297 298 299 300 301 302 303 | @ -- The difference between vfile.chnged==2 and a regular add is that @ -- with vfile.chnged==2 we know that the current version of the file @ -- is already in the repository. @ -- @ -- @ CREATE TABLE vfile( @ id INTEGER PRIMARY KEY, -- ID of the checked out file | | | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | @ -- The difference between vfile.chnged==2 and a regular add is that @ -- with vfile.chnged==2 we know that the current version of the file @ -- is already in the repository. @ -- @ -- @ CREATE TABLE vfile( @ id INTEGER PRIMARY KEY, -- ID of the checked out file @ vid INTEGER REFERENCES blob, -- The baseline this file is part of. @ chnged INT DEFAULT 0, -- 0:unchnged 1:edited 2:m-chng 3:m-add @ deleted BOOLEAN DEFAULT 0, -- True if deleted @ rid INTEGER, -- Originally from this repository record @ mrid INTEGER, -- Based on this record due to a merge @ pathname TEXT, -- Full pathname @ UNIQUE(pathname,vid) @ ); |
| ︙ | ︙ | |||
319 320 321 322 323 324 325 | @ CREATE TABLE vmerge( @ id INTEGER REFERENCES vfile, -- VFILE entry that has been merged @ merge INTEGER, -- Merged with this record @ UNIQUE(id, merge) @ ); @ ; | < < < < < < < < < < < < < < < | 319 320 321 322 323 324 325 | @ CREATE TABLE vmerge( @ id INTEGER REFERENCES vfile, -- VFILE entry that has been merged @ merge INTEGER, -- Merged with this record @ UNIQUE(id, merge) @ ); @ ; |
Changes to src/setup.c.
| ︙ | ︙ | |||
643 644 645 646 647 648 649 |
db_multi_exec("DELETE FROM config WHERE name='header'");
cgi_replace_parameter("header", zDefaultHeader);
}else{
textarea_attribute(0, 0, 0, "header", "header", zDefaultHeader);
}
style_header("Edit Page Header");
@ <form action="%s(g.zBaseURL)/setup_header" method="POST">
| | | 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 |
db_multi_exec("DELETE FROM config WHERE name='header'");
cgi_replace_parameter("header", zDefaultHeader);
}else{
textarea_attribute(0, 0, 0, "header", "header", zDefaultHeader);
}
style_header("Edit Page Header");
@ <form action="%s(g.zBaseURL)/setup_header" method="POST">
@ <p>Edit HTML text with embedded TH1 (a TCL dialect) that will be used to
@ generate the beginning of every page through start of the main
@ menu.</p>
textarea_attribute("", 40, 80, "header", "header", zDefaultHeader);
@ <br />
@ <input type="submit" name="submit" value="Apply Changes">
@ <input type="submit" name="clear" value="Revert To Default">
@ </form>
|
| ︙ | ︙ | |||
676 677 678 679 680 681 682 |
db_multi_exec("DELETE FROM config WHERE name='footer'");
cgi_replace_parameter("footer", zDefaultFooter);
}else{
textarea_attribute(0, 0, 0, "footer", "footer", zDefaultFooter);
}
style_header("Edit Page Footer");
@ <form action="%s(g.zBaseURL)/setup_footer" method="POST">
| | | 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 |
db_multi_exec("DELETE FROM config WHERE name='footer'");
cgi_replace_parameter("footer", zDefaultFooter);
}else{
textarea_attribute(0, 0, 0, "footer", "footer", zDefaultFooter);
}
style_header("Edit Page Footer");
@ <form action="%s(g.zBaseURL)/setup_footer" method="POST">
@ <p>Edit HTML text with embedded TH1 (a TCL dialect) that will be used to
@ generate the end of every page.</p>
textarea_attribute("", 20, 80, "footer", "footer", zDefaultFooter);
@ <br />
@ <input type="submit" name="submit" value="Apply Changes">
@ <input type="submit" name="clear" value="Revert To Default">
@ </form>
@ <hr>
|
| ︙ | ︙ | |||
727 728 729 730 731 732 733 |
}else{
@ <p><font color="red"><b>
@ SCRIPT ERROR: %h(zErr)
@ </b></font></p>
}
}
@ <form action="%s(g.zBaseURL)/setup_ticket" method="POST">
| | | | 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 |
}else{
@ <p><font color="red"><b>
@ SCRIPT ERROR: %h(zErr)
@ </b></font></p>
}
}
@ <form action="%s(g.zBaseURL)/setup_ticket" method="POST">
@ <p>Edit the TH1 script that defines the ticketing
@ system setup for this server.</p>
@ <textarea name="cfg" rows="40" cols="80">%h(zConfig)</textarea>
@ <br />
@ <input type="submit" name="submit" value="Apply Changes">
@ <input type="submit" name="clear" value="Revert To Default">
@ </form>
@ <hr>
@ Here is the default ticket configuration:
@ <blockquote><pre>
@ %h(zDefaultTicketConfig)
@ </pre></blockquote>
db_end_transaction(0);
}
|
Changes to src/style.c.
| ︙ | ︙ | |||
66 67 68 69 70 71 72 |
*/
static int submenuCompare(const void *a, const void *b){
const struct Submenu *A = (const struct Submenu*)a;
const struct Submenu *B = (const struct Submenu*)b;
return strcmp(A->zLabel, B->zLabel);
}
| < < < < < < < < < | | | | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
*/
static int submenuCompare(const void *a, const void *b){
const struct Submenu *A = (const struct Submenu*)a;
const struct Submenu *B = (const struct Submenu*)b;
return strcmp(A->zLabel, B->zLabel);
}
/*
** Draw the header.
*/
void style_header(const char *zTitle){
const char *zHeader = db_get("header", (char*)zDefaultHeader);
login_check_credentials();
cgi_destination(CGI_HEADER);
/* Generate the header up through the main menu */
Th_Store("project_name", db_get("project-name","Unnamed Fossil Project"));
Th_Store("title", zTitle);
Th_Store("baseurl", g.zBaseURL);
Th_Store("manifest_version", MANIFEST_VERSION);
Th_Store("manifest_date", MANIFEST_DATE);
if( g.zLogin ){
Th_Store("login", g.zLogin);
}
Th_Render(zHeader);
cgi_destination(CGI_BODY);
g.cgiPanic = 1;
}
/*
** Draw the footer at the bottom of the page.
*/
void style_footer(void){
const char *zFooter;
/* Go back and put the submenu at the top of the page. We delay the
** creation of the submenu until the end so that we can add elements
** to the submenu while generating page text.
*/
if( nSubmenu>0 ){
int i;
cgi_destination(CGI_HEADER);
|
| ︙ | ︙ | |||
160 161 162 163 164 165 166 |
}
/* Put the footer at the bottom of the page.
*/
@ <div class="content">
zFooter = db_get("footer", (char*)zDefaultFooter);
@ </div>
| | < < | | | | | | > | | | | | > > > > > > > > > > > > > > > > > > > > > > | | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
}
/* Put the footer at the bottom of the page.
*/
@ <div class="content">
zFooter = db_get("footer", (char*)zDefaultFooter);
@ </div>
Th_Render(zFooter);
}
/* @-comment: // */
/*
** The default page header.
*/
const char zDefaultHeader[] =
@ <html>
@ <head>
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$baseurl/timeline.rss">
@ <link rel="stylesheet" href="$baseurl/style.css" type="text/css"
@ media="screen">
@ </head>
@ <body>
@ <div class="header">
@ <div class="logo">
@ <!-- <img src="logo.gif" alt="logo"><br></br> -->
@ <nobr>$<project_name></nobr>
@ </div>
@ <div class="title">$<title></div>
@ <div class="status"><nobr><th1>
@ if {[info exists login]} {
@ html "Logged in as <a href='$baseurl/my'>$login</a>"
@ } else {
@ puts "Not logged in"
@ }
@ </th1></nobr></div>
@ </div>
@ <div class="mainmenu"><th1>
@ html "<a href='$baseurl/home'>Home</a>"
@ if {[hascap h]} {
@ html "<a href='$baseurl/dir'>Files</a>"
@ }
@ if {[hascap i]} {
@ html "<a href='$baseurl/leaves'>Leaves</a>"
@ html "<a href='$baseurl/timeline'>Timeline</a>"
@ html "<a href='$baseurl/tagview'>Tags</a>"
@ }
@ if {[hascap j]} {
@ html "<a href='$baseurl/wiki'>Wiki</a>"
@ }
@ if {[hascap s]} {
@ html "<a href='$baseurl/setup'>Setup</a>"
@ }
@ if {[info exists login]} {
@ html "<a href='$baseurl/login'>Login</a>"
@ } else {
@ html "<a href='$baseurl/login'>Logout</a>"
@ }
@ </th1></div>
;
/*
** The default page footer
*/
const char zDefaultFooter[] =
@ <div class="footer">
@ Fossil version $manifest_version $manifest_date
@ </div>
@ </body></html>
;
/*
** The default Cascading Style Sheet.
*/
|
| ︙ | ︙ |
Deleted src/subscript.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added src/th.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 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 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 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 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 |
/*
** The implementation of the TH core. This file contains the parser, and
** the implementation of the interface in th.h.
*/
#include "th.h"
#include <string.h>
#include <assert.h>
typedef struct Th_Command Th_Command;
typedef struct Th_Frame Th_Frame;
typedef struct Th_Variable Th_Variable;
/*
** Interpreter structure.
*/
struct Th_Interp {
Th_Vtab *pVtab; /* Copy of the argument passed to Th_CreateInterp() */
uchar *zResult; /* Current interpreter result (Th_Malloc()ed) */
int nResult; /* number of bytes in zResult */
Th_Hash *paCmd; /* Table of registered commands */
Th_Frame *pFrame; /* Current execution frame */
int isListMode; /* True if thSplitList() should operate in "list" mode */
};
/*
** Each TH command registered using Th_CreateCommand() is represented
** by an instance of the following structure stored in the Th_Interp.paCmd
** hash-table.
*/
struct Th_Command {
int (*xProc)(Th_Interp *, void *, int, const uchar **, int *);
void *pContext;
void (*xDel)(Th_Interp *, void *);
};
/*
** Each stack frame (variable scope) is represented by an instance
** of this structure. Variable values set using the Th_SetVar command
** are stored in the Th_Frame.paVar hash table member of the associated
** stack frame object.
**
** When an interpreter is created, a single Th_Frame structure is also
** allocated - the global variable scope. Th_Interp.pFrame (the current
** interpreter frame) is initialised to point to this Th_Frame. It is
** not deleted for the lifetime of the interpreter (because the global
** frame never goes out of scope).
**
** New stack frames are created by the Th_InFrame() function. Before
** invoking its callback function, Th_InFrame() allocates a new Th_Frame
** structure with pCaller set to the current frame (Th_Interp.pFrame),
** and sets the current frame to the new frame object. After the callback
** has been invoked, the allocated Th_Frame is deleted and the value
** of the current frame pointer restored.
**
** By default, the Th_SetVar(), Th_UnsetVar() and Th_GetVar() functions
** access variable values in the current frame. If they need to access
** the global frame, they do so by traversing the pCaller pointer list.
** Likewise, the Th_LinkVar() function uses the pCaller pointers to
** link to variables located in the global or other stack frames.
*/
struct Th_Frame {
Th_Hash *paVar; /* Variables defined in this scope */
Th_Frame *pCaller; /* Calling frame */
};
/*
** This structure represents a value assigned to a th1 variable.
**
** The Th_Frame.paVar hash table maps from variable name (a th1 string)
** to a pointer to an instance of the following structure. More than
** one hash table entry may map to a single structure if variable
** links have been created using Th_LinkVar(). The number of references
** is stored in Th_Variable.nRef.
**
** For scalar variables, Th_Variable.zData is never 0. Th_Variable.nData
** stores the number of bytes in the value pointed to by zData.
**
** For an array variable, Th_Variable.zData is 0 and pHash points to
** a hash table mapping between array key name (a th1 string) and
** a the pointer to the Th_Variable structure holding the scalar
** value.
*/
struct Th_Variable {
int nRef; /* Number of references to this structure */
int nData; /* Number of bytes at Th_Variable.zData */
uchar *zData; /* Data for scalar variables */
Th_Hash *pHash; /* Data for array variables */
};
/*
** Hash table API:
*/
#define TH_HASHSIZE 257
struct Th_Hash {
Th_HashEntry *a[TH_HASHSIZE];
};
static int thEvalLocal(Th_Interp *, const uchar *, int);
static int thSplitList(Th_Interp*, const uchar*, int, uchar***, int **, int*);
static int thHexdigit(uchar c);
static int thEndOfLine(const uchar *, int);
static int thPushFrame(Th_Interp*, Th_Frame*);
static void thPopFrame(Th_Interp*);
static void thFreeVariable(Th_HashEntry*, void*);
static void thFreeCommand(Th_HashEntry*, void*);
/*
** The following are used by both the expression and language parsers.
** Given that the start of the input string (z, n) is a language
** construct of the relevant type (a command enclosed in [], an escape
** sequence etc.), these functions determine the number of bytes
** of the input consumed by the construct. For example:
**
** int nByte;
** thNextCommand(interp, "[expr $a+1] $nIter", 18, &nByte);
**
** results in variable nByte being set to 11. Or,
**
** thNextVarname(interp, "$a+1", 4, &nByte);
**
** results in nByte being set to 2.
*/
static int thNextCommand(Th_Interp*, const uchar *z, int n, int *pN);
static int thNextEscape (Th_Interp*, const uchar *z, int n, int *pN);
static int thNextVarname(Th_Interp*, const uchar *z, int n, int *pN);
static int thNextNumber (Th_Interp*, const uchar *z, int n, int *pN);
static int thNextSpace (Th_Interp*, const uchar *z, int n, int *pN);
/*
** Given that the input string (z, n) contains a language construct of
** the relevant type (a command enclosed in [], an escape sequence
** like "\xFF" or a variable reference like "${varname}", perform
** substitution on the string and store the resulting string in
** the interpreter result.
*/
static int thSubstCommand(Th_Interp*, const uchar *z, int n);
static int thSubstEscape (Th_Interp*, const uchar *z, int n);
static int thSubstVarname(Th_Interp*, const uchar *z, int n);
/*
** Given that there is a th1 word located at the start of the input
** string (z, n), determine the length in bytes of that word. If the
** isCmd argument is non-zero, then an unescaped ";" byte not
** located inside of a block or quoted string is considered to mark
** the end of the word.
*/
static int thNextWord(Th_Interp*, const uchar *z, int n, int *pN, int isCmd);
/*
** Perform substitution on the word contained in the input string (z, n).
** Store the resulting string in the interpreter result.
*/
static int thSubstWord(Th_Interp*, const uchar *z, int n);
/*
** The Buffer structure and the thBufferXXX() functions are used to make
** memory allocation easier when building up a result.
*/
struct Buffer {
uchar *zBuf;
int nBuf;
int nBufAlloc;
};
typedef struct Buffer Buffer;
static int thBufferWrite(Th_Interp *interp, Buffer *, const uchar *, int);
static void thBufferInit(Buffer *);
static void thBufferFree(Th_Interp *interp, Buffer *);
/*
** Append nAdd bytes of content copied from zAdd to the end of buffer
** pBuffer. If there is not enough space currently allocated, resize
** the allocation to make space.
*/
static int thBufferWrite(
Th_Interp *interp,
Buffer *pBuffer,
const uchar *zAdd,
int nAdd
){
int nReq;
if( nAdd<0 ){
nAdd = th_strlen(zAdd);
}
nReq = pBuffer->nBuf+nAdd+1;
if( nReq>pBuffer->nBufAlloc ){
uchar *zNew;
int nNew;
nNew = nReq*2;
zNew = (uchar *)Th_Malloc(interp, nNew);
memcpy(zNew, pBuffer->zBuf, pBuffer->nBuf);
Th_Free(interp, pBuffer->zBuf);
pBuffer->nBufAlloc = nNew;
pBuffer->zBuf = zNew;
}
memcpy(&pBuffer->zBuf[pBuffer->nBuf], zAdd, nAdd);
pBuffer->nBuf += nAdd;
pBuffer->zBuf[pBuffer->nBuf] = '\0';
return TH_OK;
}
#define thBufferWrite(a,b,c,d) thBufferWrite(a,b,(const uchar *)c,d)
/*
** Initialize the Buffer structure pointed to by pBuffer.
*/
static void thBufferInit(Buffer *pBuffer){
memset(pBuffer, 0, sizeof(Buffer));
}
/*
** Zero the buffer pointed to by pBuffer and free the associated memory
** allocation.
*/
static void thBufferFree(Th_Interp *interp, Buffer *pBuffer){
Th_Free(interp, pBuffer->zBuf);
thBufferInit(pBuffer);
}
/*
** Assuming parameter c contains a hexadecimal digit character,
** return the corresponding value of that digit. If c is not
** a hexadecimal digit character, -1 is returned.
*/
static int thHexdigit(uchar c){
switch (c) {
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'a': case 'A': return 10;
case 'b': case 'B': return 11;
case 'c': case 'C': return 12;
case 'd': case 'D': return 13;
case 'e': case 'E': return 14;
case 'f': case 'F': return 15;
}
return -1;
}
/*
** Argument pEntry points to an entry in a stack frame hash table
** (Th_Frame.paVar). Decrement the refrerence count of the Th_Variable
** structure that the entry points to. Free the Th_Variable if its
** reference count reaches 0.
**
** Argument pContext is a pointer to the interpreter structure.
*/
static void thFreeVariable(Th_HashEntry *pEntry, void *pContext){
Th_Variable *pValue = (Th_Variable *)pEntry->pData;
pValue->nRef--;
assert( pValue->nRef>=0 );
if( pValue->nRef==0 ){
Th_Interp *interp = (Th_Interp *)pContext;
Th_Free(interp, pValue->zData);
if( pValue->pHash ){
Th_HashIterate(interp, pValue->pHash, thFreeVariable, pContext);
Th_HashDelete(interp, pValue->pHash);
}
Th_Free(interp, pValue);
}
}
/*
** Argument pEntry points to an entry in the command hash table
** (Th_Interp.paCmd). Delete the Th_Command structure that the
** entry points to.
**
** Argument pContext is a pointer to the interpreter structure.
*/
static void thFreeCommand(Th_HashEntry *pEntry, void *pContext){
Th_Command *pCommand = (Th_Command *)pEntry->pData;
if( pCommand->xDel ){
pCommand->xDel((Th_Interp *)pContext, pCommand->pContext);
}
Th_Free((Th_Interp *)pContext, pEntry->pData);
pEntry->pData = 0;
}
/*
** Push a new frame onto the stack.
*/
static int thPushFrame(Th_Interp *interp, Th_Frame *pFrame){
pFrame->paVar = Th_HashNew(interp);
pFrame->pCaller = interp->pFrame;
interp->pFrame = pFrame;
return TH_OK;
}
/*
** Pop a frame off the top of the stack.
*/
static void thPopFrame(Th_Interp *interp){
Th_Frame *pFrame = interp->pFrame;
Th_HashIterate(interp, pFrame->paVar, thFreeVariable, (void *)interp);
Th_HashDelete(interp, pFrame->paVar);
interp->pFrame = pFrame->pCaller;
}
/*
** The first part of the string (zInput,nInput) contains an escape
** sequence. Set *pnEscape to the number of bytes in the escape sequence.
** If there is a parse error, return TH_ERROR and set the interpreter
** result to an error message. Otherwise return TH_OK.
*/
static int thNextEscape(
Th_Interp *interp,
const uchar *zInput,
int nInput,
int *pnEscape
){
int i = 2;
assert(nInput>0);
assert(zInput[0]=='\\');
if( nInput<=1 ){
return TH_ERROR;
}
switch( zInput[1] ){
case 'x': i = 4;
}
if( i>nInput ){
return TH_ERROR;
}
*pnEscape = i;
return TH_OK;
}
/*
** The first part of the string (zInput,nInput) contains a variable
** reference. Set *pnVarname to the number of bytes in the variable
** reference. If there is a parse error, return TH_ERROR and set the
** interpreter result to an error message. Otherwise return TH_OK.
*/
int thNextVarname(
Th_Interp *interp,
const uchar *zInput,
int nInput,
int *pnVarname
){
int i;
assert(nInput>0);
assert(zInput[0]=='$');
if( nInput>0 && zInput[1]=='{' ){
for(i=2; i<nInput && zInput[i]!='}'; i++);
if( i==nInput ){
return TH_ERROR;
}
i++;
}else{
i = 1;
if( nInput>2 && zInput[1]==':' && zInput[2]==':' ){
i += 2;
}
for(; i<nInput; i++){
if( zInput[i]=='(' ){
for(i++; i<nInput; i++){
if( zInput[i]==')' ) break;
if( zInput[i]=='\\' ) i++;
if( zInput[i]=='{' || zInput[i]=='[' || zInput[i]=='"' ){
int nWord;
int rc = thNextWord(interp, &zInput[i], nInput-i, &nWord, 0);
if( rc!=TH_OK ){
return rc;
}
i += nWord;
}
}
if( i>=nInput ){
Th_ErrorMessage(interp, "Unmatched brackets:", zInput, nInput);
return TH_ERROR;
}
i++;
break;
}
if( !th_isalnum(zInput[i]) && zInput[i]!='_' ) break;
}
}
*pnVarname = i;
return TH_OK;
}
/*
** The first part of the string (zInput,nInput) contains a command
** enclosed in a "[]" block. Set *pnCommand to the number of bytes in
** the variable reference. If there is a parse error, return TH_ERROR
** and set the interpreter result to an error message. Otherwise return
** TH_OK.
*/
int thNextCommand(
Th_Interp *interp,
const uchar *zInput,
int nInput,
int *pnCommand
){
int nBrace = 0;
int nSquare = 0;
int i;
assert(nInput>0);
assert( zInput[0]=='[' || zInput[0]=='{' );
for(i=0; i<nInput && (i==0 || nBrace>0 || nSquare>0); i++){
switch( zInput[i] ){
case '\\': i++; break;
case '{': nBrace++; break;
case '}': nBrace--; break;
case '[': nSquare++; break;
case ']': nSquare--; break;
}
}
if( nBrace || nSquare ){
return TH_ERROR;
}
*pnCommand = i;
return TH_OK;
}
/*
** Set *pnSpace to the number of whitespace bytes at the start of
** input string (zInput, nInput). Always return TH_OK.
*/
int thNextSpace(
Th_Interp *interp,
const uchar *zInput,
int nInput,
int *pnSpace
){
int i;
for(i=0; i<nInput && th_isspace(zInput[i]); i++);
*pnSpace = i;
return TH_OK;
}
/*
** The first byte of the string (zInput,nInput) is not white-space.
** Set *pnWord to the number of bytes in the th1 word that starts
** with this byte. If a complete word cannot be parsed or some other
** error occurs, return TH_ERROR and set the interpreter result to
** an error message. Otherwise return TH_OK.
**
** If the isCmd argument is non-zero, then an unescaped ";" byte not
** located inside of a block or quoted string is considered to mark
** the end of the word.
*/
static int thNextWord(
Th_Interp *interp,
const uchar *zInput,
int nInput,
int *pnWord,
int isCmd
){
int iEnd = 0;
assert( !th_isspace(zInput[0]) );
if( zInput[0]=='"' ){
/* The word is terminated by the next unescaped '"' character. */
iEnd++;
while( iEnd<nInput && zInput[iEnd]!='"' ){
if( zInput[iEnd]=='\\' ){
iEnd++;
}
iEnd++;
}
iEnd++;
}else{
int nBrace = 0;
int nSq = 0;
while( iEnd<nInput && (nBrace>0 || nSq>0 ||
(!th_isspace(zInput[iEnd]) && (!isCmd || zInput[iEnd]!=';'))
)){
switch( zInput[iEnd] ){
case '\\': iEnd++; break;
case '{': if( nSq==0 ) nBrace++; break;
case '}': if( nSq==0 ) nBrace--; break;
case '[': if( nBrace==0 ) nSq++; break;
case ']': if( nBrace==0 ) nSq--; break;
}
iEnd++;
}
if( nBrace>0 || nSq>0 ){
/* Parse error */
return TH_ERROR;
}
}
if( iEnd>nInput ){
/* Parse error */
return TH_ERROR;
}
*pnWord = iEnd;
return TH_OK;
}
/*
** The input string (zWord, nWord) contains a th1 script enclosed in
** a [] block. Perform substitution on the input string and store the
** resulting string in the interpreter result.
*/
static int thSubstCommand(
Th_Interp *interp,
const uchar *zWord,
int nWord
){
assert(nWord>=2);
assert(zWord[0]=='[' && zWord[nWord-1]==']');
return thEvalLocal(interp, &zWord[1], nWord-2);
}
/*
** The input string (zWord, nWord) contains a th1 variable reference
** (a '$' byte followed by a variable name). Perform substitution on
** the input string and store the resulting string in the interpreter
** result.
*/
static int thSubstVarname(
Th_Interp *interp,
const uchar *zWord,
int nWord
){
assert(nWord>=1);
assert(zWord[0]=='$');
assert(nWord==1 || zWord[1]!='{' || zWord[nWord-1]=='}');
if( nWord>1 && zWord[1]=='{' ){
zWord++;
nWord -= 2;
}else if( zWord[nWord-1]==')' ){
int i;
for(i=1; i<nWord && zWord[i]!='('; i++);
if( i<nWord ){
Buffer varname;
int nInner;
const uchar *zInner;
int rc = thSubstWord(interp, &zWord[i+1], nWord-i-2);
if( rc!=TH_OK ) return rc;
zInner = Th_GetResult(interp, &nInner);
thBufferInit(&varname);
thBufferWrite(interp, &varname, &zWord[1], i);
thBufferWrite(interp, &varname, zInner, nInner);
thBufferWrite(interp, &varname, ")", 1);
rc = Th_GetVar(interp, varname.zBuf, varname.nBuf);
thBufferFree(interp, &varname);
return rc;
}
}
return Th_GetVar(interp, &zWord[1], nWord-1);
}
/*
** The input string (zWord, nWord) contains a th1 escape sequence.
** Perform substitution on the input string and store the resulting
** string in the interpreter result.
*/
static int thSubstEscape(
Th_Interp *interp,
const uchar *zWord,
int nWord
){
uchar c;
assert(nWord>=2);
assert(zWord[0]=='\\');
switch( zWord[1] ){
case 'x': {
assert(nWord==4);
c = ((thHexdigit(zWord[2])<<4) + thHexdigit(zWord[3]));
break;
}
case 'n': {
c = '\n';
break;
}
default: {
assert(nWord==2);
c = zWord[1];
break;
}
}
Th_SetResult(interp, &c, 1);
return TH_OK;
}
/*
** The input string (zWord, nWord) contains a th1 word. Perform
** substitution on the input string and store the resulting
** string in the interpreter result.
*/
static int thSubstWord(
Th_Interp *interp,
const uchar *zWord,
int nWord
){
int rc = TH_OK;
Buffer output;
int i;
thBufferInit(&output);
if( nWord>1 && (zWord[0]=='{' && zWord[nWord-1]=='}') ){
rc = thBufferWrite(interp, &output, &zWord[1], nWord-2);
}else{
/* If the word is surrounded by double-quotes strip these away. */
if( nWord>1 && (zWord[0]=='"' && zWord[nWord-1]=='"') ){
zWord++;
nWord -= 2;
}
for(i=0; rc==TH_OK && i<nWord; i++){
int nGet;
int (*xGet)(Th_Interp *, const uchar*, int, int *) = 0;
int (*xSubst)(Th_Interp *, const uchar*, int) = 0;
switch( zWord[i] ){
case '\\':
xGet = thNextEscape; xSubst = thSubstEscape;
break;
case '[':
if( !interp->isListMode ){
xGet = thNextCommand; xSubst = thSubstCommand;
break;
}
case '$':
if( !interp->isListMode ){
xGet = thNextVarname; xSubst = thSubstVarname;
break;
}
default: {
thBufferWrite(interp, &output, &zWord[i], 1);
continue; /* Go to the next iteration of the for(...) loop */
}
}
rc = xGet(interp, &zWord[i], nWord-i, &nGet);
if( rc==TH_OK ){
rc = xSubst(interp, &zWord[i], nGet);
}
if( rc==TH_OK ){
const uchar *zRes;
int nRes;
zRes = Th_GetResult(interp, &nRes);
rc = thBufferWrite(interp, &output, zRes, nRes);
i += (nGet-1);
}
}
}
if( rc==TH_OK ){
Th_SetResult(interp, output.zBuf, output.nBuf);
}
thBufferFree(interp, &output);
return rc;
}
/*
** Return true if one of the following is true of the buffer pointed
** to by zInput, length nInput:
**
** + It is empty, or
** + It contains nothing but white-space, or
** + It contains no non-white-space characters before the first
** newline character.
**
** Otherwise return false.
*/
static int thEndOfLine(const uchar *zInput, int nInput){
int i;
for(i=0; i<nInput && zInput[i]!='\n' && th_isspace(zInput[i]); i++);
return ((i==nInput || zInput[i]=='\n')?1:0);
}
/*
** This function splits the supplied th1 list (contained in buffer zList,
** size nList) into elements and performs word-substitution on each
** element. If the Th_Interp.isListMode variable is true, then only
** escape sequences are substituted (used by the Th_SplitList() function).
** If Th_Interp.isListMode is false, then variable and command substitution
** is also performed (used by Th_Eval()).
**
** If zList/nList does not contain a valid list, TH_ERROR is returned
** and an error message stored in interp.
**
** If TH_OK is returned and pazElem is not NULL, the caller should free the
** pointer written to (*pazElem) using Th_Free(). This releases memory
** allocated for both the (*pazElem) and (*panElem) arrays. Example:
**
** uchar **argv;
** int *argl;
** int argc;
**
** // After this call, argv and argl point to valid arrays. The
** // number of elements in each is argc.
** //
** Th_SplitList(interp, zList, nList, &argv, &argl, &argc);
**
** // Free all memory allocated by Th_SplitList(). The arrays pointed
** // to by argv and argl are invalidated by this call.
** //
** Th_Free(interp, argv);
**
*/
static int thSplitList(
Th_Interp *interp, /* Interpreter context */
const uchar *zList, /* Pointer to buffer containing input list */
int nList, /* Size of buffer pointed to by zList */
uchar ***pazElem, /* OUT: Array of list elements */
int **panElem, /* OUT: Lengths of each list element */
int *pnCount /* OUT: Number of list elements */
){
int rc = TH_OK;
Buffer strbuf;
Buffer lenbuf;
int nCount = 0;
const uchar *zInput = zList;
int nInput = nList;
thBufferInit(&strbuf);
thBufferInit(&lenbuf);
while( nInput>0 ){
const uchar *zWord;
int nWord;
thNextSpace(interp, zInput, nInput, &nWord);
zInput += nWord;
nInput = nList-(zInput-zList);
if( TH_OK!=(rc = thNextWord(interp, zInput, nInput, &nWord, 0))
|| TH_OK!=(rc = thSubstWord(interp, zInput, nWord))
){
goto finish;
}
zInput = &zInput[nWord];
nInput = nList-(zInput-zList);
if( nWord>0 ){
zWord = Th_GetResult(interp, &nWord);
thBufferWrite(interp, &strbuf, zWord, nWord);
thBufferWrite(interp, &strbuf, "\0", 1);
thBufferWrite(interp, &lenbuf, &nWord, sizeof(int));
nCount++;
}
}
assert((lenbuf.nBuf/sizeof(int))==nCount);
assert((pazElem && panElem) || (!pazElem && !panElem));
if( pazElem && rc==TH_OK ){
int i;
uchar *zElem;
int *anElem;
uchar **azElem = Th_Malloc(interp,
sizeof(uchar*) * nCount + /* azElem */
sizeof(int) * nCount + /* anElem */
strbuf.nBuf /* space for list element strings */
);
anElem = (int *)&azElem[nCount];
zElem = (uchar *)&anElem[nCount];
memcpy(anElem, lenbuf.zBuf, lenbuf.nBuf);
memcpy(zElem, strbuf.zBuf, strbuf.nBuf);
for(i=0; i<nCount;i++){
azElem[i] = zElem;
zElem += (anElem[i] + 1);
}
*pazElem = azElem;
*panElem = anElem;
}
if( pnCount ){
*pnCount = nCount;
}
finish:
thBufferFree(interp, &strbuf);
thBufferFree(interp, &lenbuf);
return rc;
}
/*
** Evaluate the th1 script contained in the string (zProgram, nProgram)
** in the current stack frame.
*/
static int thEvalLocal(Th_Interp *interp, const uchar *zProgram, int nProgram){
int rc = TH_OK;
const uchar *zInput = zProgram;
int nInput = nProgram;
while( rc==TH_OK && nInput ){
Th_HashEntry *pEntry;
int nSpace;
const uchar *zFirst;
uchar **argv;
int *argl;
int argc;
assert(nInput>=0);
/* Skip a semi-colon */
if( *zInput==';' ){
zInput++;
nInput--;
}
/* Skip past leading white-space. */
thNextSpace(interp, zInput, nInput, &nSpace);
zInput += nSpace;
nInput -= nSpace;
zFirst = zInput;
/* Check for a comment. If found, skip to the end of the line. */
if( zInput[0]=='#' ){
while( !thEndOfLine(zInput, nInput) ){
zInput++;
nInput--;
}
continue;
}
/* Gobble up input a word at a time until the end of the command
** (a semi-colon or end of line).
*/
while( rc==TH_OK && *zInput!=';' && !thEndOfLine(zInput, nInput) ){
int nWord;
thNextSpace(interp, zInput, nInput, &nSpace);
rc = thNextWord(interp, &zInput[nSpace], nInput-nSpace, &nWord, 1);
zInput += (nSpace+nWord);
nInput -= (nSpace+nWord);
}
if( rc!=TH_OK ) continue;
/* Split the command into an array of words. This call also does
** substitution of each individual word.
*/
rc = thSplitList(interp, zFirst, zInput-zFirst, &argv, &argl, &argc);
if( rc!=TH_OK ) continue;
if( argc>0 ){
/* Look up the command name in the command hash-table. */
pEntry = Th_HashFind(interp, interp->paCmd, argv[0], argl[0], 0);
if( !pEntry ){
Th_ErrorMessage(interp, "no such command: ", argv[0], argl[0]);
rc = TH_ERROR;
}
/* Call the command procedure. */
if( rc==TH_OK ){
Th_Command *p = (Th_Command *)(pEntry->pData);
const uchar **azArg = (const uchar **)argv;
rc = p->xProc(interp, p->pContext, argc, azArg, argl);
}
/* If an error occured, add this command to the stack trace report. */
if( rc==TH_ERROR ){
uchar *zRes;
int nRes;
uchar *zStack = 0;
int nStack = 0;
zRes = Th_TakeResult(interp, &nRes);
if( TH_OK==Th_GetVar(interp, (uchar *)"::th_stack_trace", -1) ){
zStack = Th_TakeResult(interp, &nStack);
}
Th_ListAppend(interp, &zStack, &nStack, zFirst, zInput-zFirst);
Th_SetVar(interp, (uchar *)"::th_stack_trace", -1, zStack, nStack);
Th_SetResult(interp, zRes, nRes);
Th_Free(interp, zRes);
Th_Free(interp, zStack);
}
}
Th_Free(interp, argv);
}
return rc;
}
/*
** Interpret an integer frame identifier passed to either Th_Eval() or
** Th_LinkVar(). If successful, return a pointer to the identified
** Th_Frame structure. If unsuccessful (no such frame), return 0 and
** leave an error message in the interpreter result.
**
** Argument iFrame is interpreted as follows:
**
** * If iFrame is 0, this means the current frame.
**
** * If iFrame is negative, then the nth frame up the stack, where
** n is the absolute value of iFrame. A value of -1 means the
** calling procedure.
**
** * If iFrame is +ve, then the nth frame from the bottom of the
** stack. An iFrame value of 1 means the toplevel (global) frame.
*/
static Th_Frame *getFrame(Th_Interp *interp, int iFrame){
Th_Frame *p = interp->pFrame;
int i;
if( iFrame>0 ){
for(i=0; p; i++){
p = p->pCaller;
}
iFrame = (i*-1) + iFrame;
p = interp->pFrame;
}
for(i=0; p && i<(iFrame*-1); i++){
p = p->pCaller;
}
if( !p ){
uchar *zFrame;
int nFrame;
Th_SetResultInt(interp, iFrame);
zFrame = Th_TakeResult(interp, &nFrame);
Th_ErrorMessage(interp, "no such frame:", zFrame, nFrame);
Th_Free(interp, zFrame);
}
return p;
}
/*
** Evaluate th1 script (zProgram, nProgram) in the frame identified by
** argument iFrame. Leave either an error message or a result in the
** interpreter result and return a th1 error code (TH_OK, TH_ERROR,
** TH_RETURN, TH_CONTINUE or TH_BREAK).
*/
int Th_Eval(Th_Interp *interp, int iFrame, const uchar *zProgram, int nProgram){
int rc = TH_OK;
Th_Frame *pSavedFrame = interp->pFrame;
/* Set Th_Interp.pFrame to the frame that this script is to be
** evaluated in. The current frame is saved in pSavedFrame and will
** be restored before this function returns.
*/
interp->pFrame = getFrame(interp, iFrame);
if( !interp->pFrame ){
rc = TH_ERROR;
}else{
int nInput = nProgram;
if( nInput<0 ){
nInput = th_strlen(zProgram);
}
rc = thEvalLocal(interp, zProgram, nInput);
}
interp->pFrame = pSavedFrame;
return rc;
}
/*
** Input string (zVarname, nVarname) contains a th1 variable name. It
** may be a simple scalar variable name or it may be a reference
** to an array member. The variable name may or may not begin with
** "::", indicating that the name refers to a global variable, not
** a local scope one.
**
** This function inspects and categorizes the supplied variable name.
**
** If the name is a global reference, *pisGlobal is set to true. Otherwise
** false. Output string (*pzOuter, *pnOuter) is set to the variable name
** if it is a scalar reference, or the name of the array if it is an
** array variable. If the variable is a scalar, *pzInner is set to 0.
** If it is an array variable, (*pzInner, *pnInner) is set to the
** array key name.
*/
static int thAnalyseVarname(
const uchar *zVarname,
int nVarname,
const uchar **pzOuter, /* OUT: Pointer to scalar/array name */
int *pnOuter, /* OUT: Number of bytes at *pzOuter */
const uchar **pzInner, /* OUT: Pointer to array key (or null) */
int *pnInner, /* OUT: Number of bytes at *pzInner */
int *pisGlobal /* OUT: Set to true if this is a global ref */
){
const uchar *zOuter = zVarname;
int nOuter;
const uchar *zInner = 0;
int nInner = 0;
int isGlobal = 0;
int i;
if( nVarname<0 ){
nVarname = th_strlen(zVarname);
}
nOuter = nVarname;
/* If the variable name starts with "::", then do the lookup is in the
** uppermost (global) frame.
*/
if( nVarname>2 && zVarname[0]==':' && zVarname[1]==':' ){
zOuter += 2;
nOuter -= 2;
isGlobal = 1;
}
/* Check if this is an array reference. */
if( zOuter[nOuter-1]==')' ){
for(i=0; i<nOuter; i++){
if( zOuter[i]=='(' ){
zInner = &zOuter[i+1];
nInner = nOuter-i-2;
nOuter = i;
break;
}
}
}
*pzOuter = zOuter;
*pnOuter = nOuter;
*pzInner = zInner;
*pnInner = nInner;
*pisGlobal = isGlobal;
return TH_OK;
}
/*
** Input string (zVar, nVar) contains a variable name. This function locates
** the Th_Variable structure associated with the named variable. The
** variable name may be a global or local scalar or array variable
**
** If the create argument is non-zero and the named variable does not exist
** it is created. Otherwise, an error is left in the interpreter result
** and NULL returned.
**
** If the arrayok argument is false and the named variable is an array,
** an error is left in the interpreter result and NULL returned. If
** arrayok is true an array name is Ok.
*/
static Th_Variable *thFindValue(
Th_Interp *interp,
const uchar *zVar, /* Pointer to variable name */
int nVar, /* Number of bytes at nVar */
int create, /* If true, create the variable if not found */
int arrayok /* If true, an array is Ok. Othewise array==error */
){
const uchar *zOuter;
int nOuter;
const uchar *zInner;
int nInner;
int isGlobal;
Th_HashEntry *pEntry;
Th_Frame *pFrame = interp->pFrame;
Th_Variable *pValue;
thAnalyseVarname(zVar, nVar, &zOuter, &nOuter, &zInner, &nInner, &isGlobal);
if( isGlobal ){
while( pFrame->pCaller ) pFrame = pFrame->pCaller;
}
pEntry = Th_HashFind(interp, pFrame->paVar, zOuter, nOuter, create);
assert(pEntry || !create);
if( !pEntry ){
goto no_such_var;
}
pValue = (Th_Variable *)pEntry->pData;
if( !pValue ){
assert(create);
pValue = Th_Malloc(interp, sizeof(Th_Variable));
pValue->nRef = 1;
pEntry->pData = (void *)pValue;
}
if( zInner ){
if( pValue->zData ){
Th_ErrorMessage(interp, "variable is a scalar:", zOuter, nOuter);
return 0;
}
if( !pValue->pHash ){
if( !create ){
goto no_such_var;
}
pValue->pHash = Th_HashNew(interp);
}
pEntry = Th_HashFind(interp, pValue->pHash, zInner, nInner, create);
if( !pEntry ){
goto no_such_var;
}
pValue = (Th_Variable *)pEntry->pData;
if( !pValue ){
assert(create);
pValue = Th_Malloc(interp, sizeof(Th_Variable));
pValue->nRef = 1;
pEntry->pData = (void *)pValue;
}
}else{
if( pValue->pHash && !arrayok ){
Th_ErrorMessage(interp, "variable is an array:", zOuter, nOuter);
return 0;
}
}
return pValue;
no_such_var:
Th_ErrorMessage(interp, "no such variable:", zVar, nVar);
return 0;
}
/*
** String (zVar, nVar) must contain the name of a scalar variable or
** array member. Look up the variable, store its current value in
** the interpreter result and return TH_OK.
**
** If the named variable does not exist, return TH_ERROR and leave
** an error message in the interpreter result.
*/
int Th_GetVar(Th_Interp *interp, const uchar *zVar, int nVar){
Th_Variable *pValue;
pValue = thFindValue(interp, zVar, nVar, 0, 0);
if( !pValue ){
return TH_ERROR;
}
if( !pValue->zData ){
Th_ErrorMessage(interp, "no such variable:", zVar, nVar);
return TH_ERROR;
}
return Th_SetResult(interp, pValue->zData, pValue->nData);
}
/*
** String (zVar, nVar) must contain the name of a scalar variable or
** array member. If the variable does not exist it is created. The
** variable is set to the value supplied in string (zValue, nValue).
**
** If (zVar, nVar) refers to an existing array, TH_ERROR is returned
** and an error message left in the interpreter result.
*/
int Th_SetVar(
Th_Interp *interp,
const uchar *zVar,
int nVar,
const uchar *zValue,
int nValue
){
Th_Variable *pValue;
pValue = thFindValue(interp, zVar, nVar, 1, 0);
if( !pValue ){
return TH_ERROR;
}
if( nValue<0 ){
nValue = th_strlen(zValue);
}
if( pValue->zData ){
Th_Free(interp, pValue->zData);
pValue->zData = 0;
}
assert(zValue || nValue==0);
pValue->zData = Th_Malloc(interp, nValue+1);
pValue->zData[nValue] = '\0';
memcpy(pValue->zData, zValue, nValue);
pValue->nData = nValue;
return TH_OK;
}
/*
** Create a variable link so that accessing variable (zLocal, nLocal) is
** the same as accessing variable (zLink, nLink) in stack frame iFrame.
*/
int Th_LinkVar(
Th_Interp *interp, /* Interpreter */
const uchar *zLocal, int nLocal, /* Local varname */
int iFrame, /* Stack frame of linked var */
const uchar *zLink, int nLink /* Linked varname */
){
Th_Frame *pSavedFrame = interp->pFrame;
Th_Frame *pFrame;
Th_HashEntry *pEntry;
Th_Variable *pValue;
pFrame = getFrame(interp, iFrame);
if( !pFrame ){
return TH_ERROR;
}
pSavedFrame = interp->pFrame;
interp->pFrame = pFrame;
pValue = thFindValue(interp, zLink, nLink, 1, 1);
interp->pFrame = pSavedFrame;
pEntry = Th_HashFind(interp, interp->pFrame->paVar, zLocal, nLocal, 1);
if( pEntry->pData ){
Th_ErrorMessage(interp, "variable exists:", zLocal, nLocal);
return TH_ERROR;
}
pEntry->pData = (void *)pValue;
pValue->nRef++;
return TH_OK;
}
/*
** Input string (zVar, nVar) must contain the name of a scalar variable,
** an array, or an array member. If the identified variable exists, it
** is deleted and TH_OK returned. Otherwise, an error message is left
** in the interpreter result and TH_ERROR is returned.
*/
int Th_UnsetVar(Th_Interp *interp, const uchar *zVar, int nVar){
Th_Variable *pValue;
pValue = thFindValue(interp, zVar, nVar, 1, 1);
if( !pValue ){
return TH_ERROR;
}
Th_Free(interp, pValue->zData);
pValue->zData = 0;
if( pValue->pHash ){
Th_HashIterate(interp, pValue->pHash, thFreeVariable, (void *)interp);
Th_HashDelete(interp, pValue->pHash);
pValue->pHash = 0;
}
return TH_OK;
}
/*
** Return an allocated buffer containing a copy of string (z, n). The
** caller is responsible for eventually calling Th_Free() to free
** the returned buffer.
*/
uchar *th_strdup(Th_Interp *interp, const uchar *z, int n){
uchar *zRes;
if( n<0 ){
n = th_strlen(z);
}
zRes = Th_Malloc(interp, n+1);
memcpy(zRes, z, n);
zRes[n] = '\0';
return zRes;
}
/*
** Argument zPre must be a nul-terminated string. Set the interpreter
** result to a string containing the contents of zPre, followed by
** a space (" ") character, followed by a copy of string (z, n).
**
** In other words, the equivalent of:
*
** printf("%s %.*s", zPre, n, z);
**
** Example:
**
** Th_ErrorMessage(interp, "no such variable:", zVarname, nVarname);
**
*/
int Th_ErrorMessage(Th_Interp *interp, const char *zPre, const uchar *z, int n){
if( interp ){
uchar *zRes = 0;
int nRes = 0;
int nPre = th_strlen(zPre);
Th_SetVar(interp, (uchar *)"::th_stack_trace", -1, 0, 0);
Th_StringAppend(interp, &zRes, &nRes, zPre, -1);
if( zRes[nRes-1]=='"' ){
Th_StringAppend(interp, &zRes, &nRes, z, n);
Th_StringAppend(interp, &zRes, &nRes, (const uchar *)"\"", 1);
}else{
Th_StringAppend(interp, &zRes, &nRes, (const uchar *)" ", 1);
Th_StringAppend(interp, &zRes, &nRes, z, n);
}
Th_SetResult(interp, zRes, nRes);
Th_Free(interp, zRes);
}
return TH_OK;
}
/*
** Set the current interpreter result by taking a copy of the buffer
** pointed to by z, size n bytes. TH_OK is always returned.
*/
int Th_SetResult(Th_Interp *pInterp, const uchar *z, int n){
/* Free the current result */
Th_Free(pInterp, pInterp->zResult);
pInterp->zResult = 0;
pInterp->nResult = 0;
if( n<0 ){
n = th_strlen(z);
}
if( z && n>0 ){
uchar *zResult;
zResult = Th_Malloc(pInterp, n+1);
memcpy(zResult, z, n);
zResult[n] = '\0';
pInterp->zResult = zResult;
pInterp->nResult = n;
}
return TH_OK;
}
/*
** Return a pointer to the buffer containing the current interpreter
** result. If pN is not NULL, set *pN to the size of the returned
** buffer.
*/
const uchar *Th_GetResult(Th_Interp *pInterp, int *pN){
assert(pInterp->zResult || pInterp->nResult==0);
if( pN ){
*pN = pInterp->nResult;
}
return (pInterp->zResult ? pInterp->zResult : (const uchar *)"");
}
/*
** Return a pointer to the buffer containing the current interpreter
** result. If pN is not NULL, set *pN to the size of the returned
** buffer.
**
** This function is the same as Th_GetResult() except that the
** caller is responsible for eventually calling Th_Free() on the
** returned buffer. The internal interpreter result is cleared
** after this function is called.
*/
uchar *Th_TakeResult(Th_Interp *pInterp, int *pN){
if( pN ){
*pN = pInterp->nResult;
}
if( pInterp->zResult ){
uchar *zResult = pInterp->zResult;
pInterp->zResult = 0;
pInterp->nResult = 0;
return zResult;
}else{
return (uchar *)Th_Malloc(pInterp, 1);
}
}
/*
** Wrappers around the supplied malloc() and free()
*/
void *Th_Malloc(Th_Interp *pInterp, int nByte){
void *p = pInterp->pVtab->xMalloc(nByte);
if( p ){
memset(p, 0, nByte);
}
return p;
}
void Th_Free(Th_Interp *pInterp, void *z){
if( z ){
pInterp->pVtab->xFree(z);
}
}
/*
** Install a new th1 command.
**
** If a command of the same name already exists, it is deleted automatically.
*/
int Th_CreateCommand(
Th_Interp *interp,
const char *zName, /* New command name */
Th_CommandProc xProc, /* Command callback proc */
void *pContext, /* Value to pass as second arg to xProc */
void (*xDel)(Th_Interp *, void *) /* Command destructor callback */
){
Th_HashEntry *pEntry;
Th_Command *pCommand;
pEntry = Th_HashFind(interp, interp->paCmd, (const uchar *)zName, -1, 1);
if( pEntry->pData ){
pCommand = pEntry->pData;
if( pCommand->xDel ){
pCommand->xDel(interp, pCommand->pContext);
}
}else{
pCommand = Th_Malloc(interp, sizeof(Th_Command));
}
pCommand->xProc = xProc;
pCommand->pContext = pContext;
pCommand->xDel = xDel;
pEntry->pData = (void *)pCommand;
return TH_OK;
}
/*
** Rename the existing command (zName, nName) to (zNew, nNew). If nNew is 0,
** the command is deleted instead of renamed.
**
** If successful, TH_OK is returned. If command zName does not exist, or
** if command zNew already exists, an error message is left in the
** interpreter result and TH_ERROR is returned.
*/
int Th_RenameCommand(
Th_Interp *interp,
const uchar *zName, /* Existing command name */
int nName, /* Number of bytes at zName */
const uchar *zNew, /* New command name */
int nNew /* Number of bytes at zNew */
){
Th_HashEntry *pEntry;
Th_HashEntry *pNewEntry;
pEntry = Th_HashFind(interp, interp->paCmd, zName, nName, 0);
if( !pEntry ){
Th_ErrorMessage(interp, "no such command:", zName, nName);
return TH_ERROR;
}
assert(pEntry->pData);
if( nNew>0 ){
pNewEntry = Th_HashFind(interp, interp->paCmd, zNew, nNew, 1);
if( pNewEntry->pData ){
Th_ErrorMessage(interp, "command exists:", zNew, nNew);
return TH_ERROR;
}
pNewEntry->pData = pEntry->pData;
}else{
Th_Command *pCommand = (Th_Command *)(pEntry->pData);
if( pCommand->xDel ){
pCommand->xDel(interp, pCommand->pContext);
}
Th_Free(interp, pCommand);
}
Th_HashFind(interp, interp->paCmd, zName, nName, -1);
return TH_OK;
}
/*
** Push a stack frame onto the interpreter stack, invoke the
** callback, and pop the frame back off again. See the implementation
** of [proc] (th_lang.c) for an example.
*/
int Th_InFrame(Th_Interp *interp,
int (*xCall)(Th_Interp *, void *pContext1, void *pContext2),
void *pContext1,
void *pContext2
){
Th_Frame frame;
int rc;
thPushFrame(interp, &frame);
rc = xCall(interp, pContext1, pContext2);
thPopFrame(interp);
return rc;
}
/*
** Split a th1 list into its component elements. The list to split is
** passed via arguments (zList, nList). If successful, TH_OK is returned.
** If an error occurs (if (zList, nList) is not a valid list) an error
** message is left in the interpreter result and TH_ERROR returned.
**
** If successful, *pnCount is set to the number of elements in the list.
** panElem is set to point at an array of *pnCount integers - the lengths
** of the element values. *pazElem is set to point at an array of
** pointers to buffers containing the array element's data.
**
** To free the arrays allocated at *pazElem and *panElem, the caller
** should call Th_Free() on *pazElem only. Exactly one such call to
** Th_Free() must be made per call to Th_SplitList().
**
** Example:
**
** int nElem;
** int *anElem;
** uchar **azElem;
** int i;
**
** Th_SplitList(interp, zList, nList, &azElem, &anElem, &nElem);
** for(i=0; i<nElem; i++){
** int nData = anElem[i];
** uchar *zData = azElem[i];
** ...
** }
**
** Th_Free(interp, azElem);
**
*/
int Th_SplitList(
Th_Interp *interp,
const uchar *zList, /* Pointer to buffer containing list */
int nList, /* Number of bytes at zList */
uchar ***pazElem, /* OUT: Array of pointers to element data */
int **panElem, /* OUT: Array of element data lengths */
int *pnCount /* OUT: Number of elements in list */
){
int rc;
interp->isListMode = 1;
rc = thSplitList(interp, zList, nList, pazElem, panElem, pnCount);
interp->isListMode = 0;
if( rc ){
Th_ErrorMessage(interp, "Expected list, got: \"", zList, nList);
}
return rc;
}
/*
** Append a new element to an existing th1 list. The element to append
** to the list is (zElem, nElem).
**
** A pointer to the existing list must be stored at *pzList when this
** function is called. The length must be stored in *pnList. The value
** of *pzList must either be NULL (in which case *pnList must be 0), or
** a pointer to memory obtained from Th_Malloc().
**
** This function calls Th_Free() to free the buffer at *pzList and sets
** *pzList to point to a new buffer containing the new list value. *pnList
** is similarly updated before returning. The return value is always TH_OK.
**
** Example:
**
** uchar *zList = 0;
** int nList = 0;
** for (...) {
** uchar *zElem = <some expression>;
** Th_ListAppend(interp, &zList, &nList, zElem, -1);
** }
** Th_SetResult(interp, zList, nList);
** Th_Free(interp, zList);
**
*/
int Th_ListAppend(
Th_Interp *interp, /* Interpreter context */
uchar **pzList, /* IN/OUT: Ptr to ptr to list */
int *pnList, /* IN/OUT: Current length of *pzList */
const uchar *zElem, /* Data to append */
int nElem /* Length of nElem */
){
Buffer output;
int i;
int hasSpecialChar = 0;
int hasEscapeChar = 0;
int nBrace = 0;
output.zBuf = *pzList;
output.nBuf = *pnList;
output.nBufAlloc = output.nBuf;
if( nElem<0 ){
nElem = th_strlen(zElem);
}
if( output.nBuf>0 ){
thBufferWrite(interp, &output, " ", 1);
}
for(i=0; i<nElem; i++){
uchar c = zElem[i];
if( th_isspecial(c) ) hasSpecialChar = 1;
if( c=='\\' ) hasEscapeChar = 1;
if( c=='{' ) nBrace++;
if( c=='}' ) nBrace--;
}
if( nElem==0 || (!hasEscapeChar && hasSpecialChar && nBrace==0) ){
thBufferWrite(interp, &output, "{", 1);
thBufferWrite(interp, &output, zElem, nElem);
thBufferWrite(interp, &output, "}", 1);
}else{
for(i=0; i<nElem; i++){
uchar c = zElem[i];
if( th_isspecial(c) ) thBufferWrite(interp, &output, "\\", 1);
thBufferWrite(interp, &output, &c, 1);
}
}
*pzList = output.zBuf;
*pnList = output.nBuf;
return TH_OK;
}
/*
** Append a new element to an existing th1 string. This function uses
** the same interface as the Th_ListAppend() function.
*/
int Th_StringAppend(
Th_Interp *interp, /* Interpreter context */
uchar **pzStr, /* IN/OUT: Ptr to ptr to list */
int *pnStr, /* IN/OUT: Current length of *pzStr */
const uchar *zElem, /* Data to append */
int nElem /* Length of nElem */
){
uchar *zNew;
int nNew;
if( nElem<0 ){
nElem = th_strlen(zElem);
}
nNew = *pnStr + nElem;
zNew = Th_Malloc(interp, nNew);
memcpy(zNew, *pzStr, *pnStr);
memcpy(&zNew[*pnStr], zElem, nElem);
Th_Free(interp, *pzStr);
*pzStr = zNew;
*pnStr = nNew;
return TH_OK;
}
/*
** Delete an interpreter.
*/
void Th_DeleteInterp(Th_Interp *interp){
assert(interp->pFrame);
assert(0==interp->pFrame->pCaller);
/* Delete the contents of the global frame. */
thPopFrame(interp);
/* Delete any result currently stored in the interpreter. */
Th_SetResult(interp, 0, 0);
/* Delete all registered commands and the command hash-table itself. */
Th_HashIterate(interp, interp->paCmd, thFreeCommand, (void *)interp);
Th_HashDelete(interp, interp->paCmd);
/* Delete the interpreter structure itself. */
Th_Free(interp, (void *)interp);
}
/*
** Create a new interpreter.
*/
Th_Interp * Th_CreateInterp(Th_Vtab *pVtab){
Th_Interp *p;
/* Allocate and initialise the interpreter and the global frame */
p = pVtab->xMalloc(sizeof(Th_Interp) + sizeof(Th_Frame));
memset(p, 0, sizeof(Th_Interp));
p->pVtab = pVtab;
p->paCmd = Th_HashNew(p);
thPushFrame(p, (Th_Frame *)&p[1]);
return p;
}
/*
** These two types are used only by the expression module, where
** the expression module means the Th_Expr() and exprXXX() functions.
*/
typedef struct Operator Operator;
struct Operator {
const char *zOp;
int eOp;
int iPrecedence;
int eArgType;
};
typedef struct Expr Expr;
struct Expr {
Operator *pOp;
Expr *pParent;
Expr *pLeft;
Expr *pRight;
uchar *zValue; /* Pointer to literal value */
int nValue; /* Length of literal value buffer */
};
/* Unary operators */
#define OP_UNARY_MINUS 2
#define OP_UNARY_PLUS 3
#define OP_BITWISE_NOT 4
#define OP_LOGICAL_NOT 5
/* Binary operators */
#define OP_MULTIPLY 6
#define OP_DIVIDE 7
#define OP_MODULUS 8
#define OP_ADD 9
#define OP_SUBTRACT 10
#define OP_LEFTSHIFT 11
#define OP_RIGHTSHIFT 12
#define OP_LT 13
#define OP_GT 14
#define OP_LE 15
#define OP_GE 16
#define OP_EQ 17
#define OP_NE 18
#define OP_SEQ 19
#define OP_SNE 20
#define OP_BITWISE_AND 21
#define OP_BITWISE_XOR 22
#define OP_BITWISE_OR 24
#define OP_LOGICAL_AND 25
#define OP_LOGICAL_OR 26
/* Other symbols */
#define OP_OPEN_BRACKET 27
#define OP_CLOSE_BRACKET 28
/* Argument types. Each operator in the expression syntax is defined
** as requiring either integer, number (real or integer) or string
** operands.
*/
#define ARG_INTEGER 1
#define ARG_NUMBER 2
#define ARG_STRING 3
static Operator aOperator[] = {
{"(", OP_OPEN_BRACKET, -1, 0},
{")", OP_CLOSE_BRACKET, -1, 0},
/* Note: all unary operators have (iPrecedence==1) */
{"-", OP_UNARY_MINUS, 1, ARG_NUMBER},
{"+", OP_UNARY_PLUS, 1, ARG_NUMBER},
{"~", OP_BITWISE_NOT, 1, ARG_INTEGER},
{"!", OP_LOGICAL_NOT, 1, ARG_INTEGER},
/* Binary operators. It is important to the parsing in Th_Expr() that
* the two-character symbols ("==") appear before the one-character
* ones ("="). And that the priorities of all binary operators are
* integers between 2 and 12.
*/
{"<<", OP_LEFTSHIFT, 4, ARG_INTEGER},
{">>", OP_RIGHTSHIFT, 4, ARG_INTEGER},
{"<=", OP_LE, 5, ARG_NUMBER},
{">=", OP_GE, 5, ARG_NUMBER},
{"==", OP_EQ, 6, ARG_NUMBER},
{"!=", OP_NE, 6, ARG_NUMBER},
{"eq", OP_SEQ, 7, ARG_STRING},
{"ne", OP_SNE, 7, ARG_STRING},
{"&&", OP_LOGICAL_AND, 11, ARG_INTEGER},
{"||", OP_LOGICAL_OR, 12, ARG_INTEGER},
{"*", OP_MULTIPLY, 2, ARG_NUMBER},
{"/", OP_DIVIDE, 2, ARG_NUMBER},
{"%", OP_MODULUS, 2, ARG_INTEGER},
{"+", OP_ADD, 3, ARG_NUMBER},
{"-", OP_SUBTRACT, 3, ARG_NUMBER},
{"<", OP_LT, 5, ARG_NUMBER},
{">", OP_GT, 5, ARG_NUMBER},
{"&", OP_BITWISE_AND, 8, ARG_INTEGER},
{"^", OP_BITWISE_XOR, 9, ARG_INTEGER},
{"|", OP_BITWISE_OR, 10, ARG_INTEGER},
{0,0,0}
};
/*
** The first part of the string (zInput,nInput) contains a number.
** Set *pnVarname to the number of bytes in the numeric string.
*/
static int thNextNumber(
Th_Interp *interp,
const uchar *zInput,
int nInput,
int *pnLiteral
){
int i;
int seenDot = 0;
for(i=0; i<nInput; i++){
uchar c = zInput[i];
if( (seenDot || c!='.') && !th_isdigit(c) ) break;
if( c=='.' ) seenDot = 1;
}
*pnLiteral = i;
return TH_OK;
}
/*
** Free an expression tree.
*/
static void exprFree(Th_Interp *interp, Expr *pExpr){
if( pExpr ){
exprFree(interp, pExpr->pLeft);
exprFree(interp, pExpr->pRight);
Th_Free(interp, pExpr->zValue);
Th_Free(interp, pExpr);
}
}
/*
** Evaluate an expression tree.
*/
static int exprEval(Th_Interp *interp, Expr *pExpr){
int rc = TH_OK;
if( pExpr->pOp==0 ){
/* A literal */
rc = thSubstWord(interp, pExpr->zValue, pExpr->nValue);
}else{
int eArgType; /* Actual type of arguments */
/* Argument values */
int iLeft;
int iRight;
double fLeft;
double fRight;
/* Left and right arguments as strings */
uchar *zLeft = 0; int nLeft;
uchar *zRight = 0; int nRight;
/* Evaluate left and right arguments, if they exist. */
if( pExpr->pLeft ){
rc = exprEval(interp, pExpr->pLeft);
if( rc==TH_OK ){
zLeft = Th_TakeResult(interp, &nLeft);
}
}
if( rc==TH_OK && pExpr->pRight ){
rc = exprEval(interp, pExpr->pRight);
if( rc==TH_OK ){
zRight = Th_TakeResult(interp, &nRight);
}
}
/* Convert arguments to their required forms. */
if( rc==TH_OK ){
eArgType = pExpr->pOp->eArgType;
if( eArgType==ARG_NUMBER ){
if( (zLeft==0 || TH_OK==Th_ToInt(0, zLeft, nLeft, &iLeft))
&& (zRight==0 || TH_OK==Th_ToInt(0, zRight, nRight, &iRight))
){
eArgType = ARG_INTEGER;
}else if(
(zLeft && TH_OK!=Th_ToDouble(interp, zLeft, nLeft, &fLeft)) ||
(zRight && TH_OK!=Th_ToDouble(interp, zRight, nRight, &fRight))
){
/* A type error. */
rc = TH_ERROR;
}
}else if( eArgType==ARG_INTEGER ){
rc = Th_ToInt(interp, zLeft, nLeft, &iLeft);
if( rc==TH_OK && zRight ){
rc = Th_ToInt(interp, zRight, nRight, &iRight);
}
}
}
if( rc==TH_OK && eArgType==ARG_INTEGER ){
int iRes;
switch( pExpr->pOp->eOp ) {
case OP_MULTIPLY: iRes = iLeft*iRight; break;
case OP_DIVIDE: iRes = iLeft/iRight; break;
case OP_MODULUS: iRes = iLeft%iRight; break;
case OP_ADD: iRes = iLeft+iRight; break;
case OP_SUBTRACT: iRes = iLeft-iRight; break;
case OP_LEFTSHIFT: iRes = iLeft<<iRight; break;
case OP_RIGHTSHIFT: iRes = iLeft>>iRight; break;
case OP_LT: iRes = iLeft<iRight; break;
case OP_GT: iRes = iLeft>iRight; break;
case OP_LE: iRes = iLeft<=iRight; break;
case OP_GE: iRes = iLeft>=iRight; break;
case OP_EQ: iRes = iLeft==iRight; break;
case OP_NE: iRes = iLeft!=iRight; break;
case OP_BITWISE_AND: iRes = iLeft&iRight; break;
case OP_BITWISE_XOR: iRes = iLeft^iRight; break;
case OP_BITWISE_OR: iRes = iLeft|iRight; break;
case OP_LOGICAL_AND: iRes = iLeft&&iRight; break;
case OP_LOGICAL_OR: iRes = iLeft||iRight; break;
case OP_UNARY_MINUS: iRes = -iLeft; break;
case OP_UNARY_PLUS: iRes = +iLeft; break;
case OP_LOGICAL_NOT: iRes = !iLeft; break;
default: assert(!"Internal error");
}
Th_SetResultInt(interp, iRes);
}else if( rc==TH_OK && eArgType==ARG_NUMBER ){
switch( pExpr->pOp->eOp ) {
case OP_MULTIPLY: Th_SetResultDouble(interp, fLeft*fRight); break;
case OP_DIVIDE: Th_SetResultDouble(interp, fLeft/fRight); break;
case OP_ADD: Th_SetResultDouble(interp, fLeft+fRight); break;
case OP_SUBTRACT: Th_SetResultDouble(interp, fLeft-fRight); break;
case OP_LT: Th_SetResultInt(interp, fLeft<fRight); break;
case OP_GT: Th_SetResultInt(interp, fLeft>fRight); break;
case OP_LE: Th_SetResultInt(interp, fLeft<=fRight); break;
case OP_GE: Th_SetResultInt(interp, fLeft>=fRight); break;
case OP_EQ: Th_SetResultInt(interp, fLeft==fRight); break;
case OP_NE: Th_SetResultInt(interp, fLeft!=fRight); break;
default: assert(!"Internal error");
}
}else if( rc==TH_OK ){
int iEqual = 0;
assert( eArgType==ARG_STRING );
if( nRight==nLeft && 0==memcmp(zRight, zLeft, nRight) ){
iEqual = 1;
}
switch( pExpr->pOp->eOp ) {
case OP_SEQ: Th_SetResultInt(interp, iEqual); break;
case OP_SNE: Th_SetResultInt(interp, !iEqual); break;
default: assert(!"Internal error");
}
}
Th_Free(interp, zLeft);
Th_Free(interp, zRight);
}
return rc;
}
/*
** Create an expression tree from an array of tokens. If successful,
** the root of the tree is stored in apToken[0].
*/
int exprMakeTree(Th_Interp *interp, Expr **apToken, int nToken){
int iLeft;
int i;
int jj;
assert(nToken>0);
#define ISTERM(x) (apToken[x] && (!apToken[x]->pOp || apToken[x]->pLeft))
for(jj=0; jj<nToken; jj++){
if( apToken[jj]->pOp && apToken[jj]->pOp->eOp==OP_OPEN_BRACKET ){
int nNest = 1;
int iLeft = jj;
for(jj++; jj<nToken; jj++){
Operator *pOp = apToken[jj]->pOp;
if( pOp && pOp->eOp==OP_OPEN_BRACKET ) nNest++;
if( pOp && pOp->eOp==OP_CLOSE_BRACKET ) nNest--;
if( nNest==0 ) break;
}
if( jj==nToken ){
return TH_ERROR;
}
if( (jj-iLeft)>1 ){
if( exprMakeTree(interp, &apToken[iLeft+1], jj-iLeft-1) ){
return TH_ERROR;
}
exprFree(interp, apToken[jj]);
exprFree(interp, apToken[iLeft]);
apToken[jj] = 0;
apToken[iLeft] = 0;
}
}
}
iLeft = 0;
for(jj=nToken-1; jj>=0; jj--){
if( apToken[jj] ){
if( apToken[jj]->pOp && apToken[jj]->pOp->iPrecedence==1 && iLeft>0 ){
apToken[jj]->pLeft = apToken[iLeft];
apToken[jj]->pLeft->pParent = apToken[jj];
apToken[iLeft] = 0;
}
iLeft = jj;
}
}
for(i=2; i<=12; i++){
iLeft = -1;
for(jj=0; jj<nToken; jj++){
Expr *pToken = apToken[jj];
if( apToken[jj] ){
if( pToken->pOp && !pToken->pLeft && pToken->pOp->iPrecedence==i ){
int iRight = jj+1;
iRight = jj+1;
for(iRight=jj+1; !apToken[iRight] && iRight<nToken; iRight++);
if( iRight==nToken || iLeft<0 || !ISTERM(iRight) || !ISTERM(iLeft) ){
return TH_ERROR;
}
pToken->pLeft = apToken[iLeft];
apToken[iLeft] = 0;
pToken->pLeft->pParent = pToken;
pToken->pRight = apToken[iRight];
apToken[iRight] = 0;
pToken->pRight->pParent = pToken;
}
iLeft = jj;
}
}
}
for(jj=1; jj<nToken; jj++){
assert( !apToken[jj] || !apToken[0] );
if( apToken[jj] ){
apToken[0] = apToken[jj];
apToken[jj] = 0;
}
}
return TH_OK;
}
/*
** Parse a string containing a TH expression to a list of tokens.
*/
static int exprParse(
Th_Interp *interp, /* Interpreter to leave error message in */
const uchar *zExpr, /* Pointer to input string */
int nExpr, /* Number of bytes at zExpr */
Expr ***papToken, /* OUT: Array of tokens. */
int *pnToken /* OUT: Size of token array */
){
int i;
int rc = TH_OK;
int nToken = 0;
Expr **apToken = 0;
for(i=0; rc==TH_OK && i<nExpr; ){
uchar c = zExpr[i];
if( th_isspace(c) ){ /* White-space */
i++;
}else{
Expr *pNew = (Expr *)Th_Malloc(interp, sizeof(Expr));
const uchar *z = &zExpr[i];
switch (c) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
thNextNumber(interp, z, nExpr-i, &pNew->nValue);
break;
case '$':
thNextVarname(interp, z, nExpr-i, &pNew->nValue);
break;
case '{': case '[': {
thNextCommand(interp, z, nExpr-i, &pNew->nValue);
break;
}
case '"': {
int iEnd = i;
while( ++iEnd<nExpr && zExpr[iEnd]!='"' ){
if( zExpr[iEnd]=='\\' ) iEnd++;
}
if( iEnd<nExpr ){
pNew->nValue = iEnd+1-i;
}
break;
}
default: {
int j;
for(j=0; aOperator[j].zOp; j++){
int nOp;
if( aOperator[j].iPrecedence==1 && nToken>0 ){
Expr *pPrev = apToken[nToken-1];
if( !pPrev->pOp || pPrev->pOp->eOp==OP_CLOSE_BRACKET ){
continue;
}
}
nOp = th_strlen((const uchar *)aOperator[j].zOp);
if( (nExpr-i)>=nOp && 0==memcmp(aOperator[j].zOp, &zExpr[i], nOp) ){
pNew->pOp = &aOperator[j];
i += nOp;
break;
}
}
}
}
if( pNew->pOp || pNew->nValue ){
if( pNew->nValue ){
/* A terminal. Copy the string value. */
assert( !pNew->pOp );
pNew->zValue = Th_Malloc(interp, pNew->nValue);
memcpy(pNew->zValue, z, pNew->nValue);
i += pNew->nValue;
}
if( (nToken%16)==0 ){
/* Grow the apToken array. */
Expr **apTokenOld = apToken;
apToken = Th_Malloc(interp, sizeof(Expr *)*(nToken+16));
memcpy(apToken, apTokenOld, sizeof(Expr *)*nToken);
}
/* Put the new token at the end of the apToken array */
apToken[nToken] = pNew;
nToken++;
}else{
Th_Free(interp, pNew);
rc = TH_ERROR;
}
}
}
*papToken = apToken;
*pnToken = nToken;
return rc;
}
/*
** Evaluate the string (zExpr, nExpr) as a Th expression. Store
** the result in the interpreter interp and return TH_OK if
** successful. If an error occurs, store an error message in
** the interpreter result and return an error code.
*/
int Th_Expr(Th_Interp *interp, const uchar *zExpr, int nExpr){
int rc; /* Return Code */
int i; /* Loop counter */
int nToken = 0;
Expr **apToken = 0;
if( nExpr<0 ){
nExpr = th_strlen(zExpr);
}
/* Parse the expression to a list of tokens. */
rc = exprParse(interp, zExpr, nExpr, &apToken, &nToken);
/* If the parsing was successful, create an expression tree from
** the parsed list of tokens. If successful, apToken[0] is set
** to point to the root of the expression tree.
*/
if( rc==TH_OK ){
rc = exprMakeTree(interp, apToken, nToken);
}
if( rc!=TH_OK ){
Th_ErrorMessage(interp, "syntax error in expression: \"", zExpr, nExpr);
}
/* Evaluate the expression tree. */
if( rc==TH_OK ){
rc = exprEval(interp, apToken[0]);
}
/* Free memory allocated by exprParse(). */
for(i=0; i<nToken; i++){
exprFree(interp, apToken[i]);
}
Th_Free(interp, apToken);
return rc;
}
/*
** Allocate and return a pointer to a new hash-table. The caller should
** (eventually) delete the hash-table by passing it to Th_HashDelete().
*/
Th_Hash *Th_HashNew(Th_Interp *interp){
Th_Hash *p;
p = Th_Malloc(interp, sizeof(Th_Hash));
return p;
}
/*
** Iterate through all values currently stored in the hash table. Invoke
** the callback function xCallback for each entry. The second argument
** passed to xCallback is a copy of the fourth argument passed to this
** function.
*/
void Th_HashIterate(
Th_Interp *interp,
Th_Hash *pHash,
void (*xCallback)(Th_HashEntry *pEntry, void *pContext),
void *pContext
){
int i;
for(i=0; i<TH_HASHSIZE; i++){
Th_HashEntry *pEntry;
Th_HashEntry *pNext;
for(pEntry=pHash->a[i]; pEntry; pEntry=pNext){
pNext = pEntry->pNext;
xCallback(pEntry, pContext);
}
}
}
/*
** Helper function for Th_HashDelete().
*/
static void xFreeHashEntry(Th_HashEntry *pEntry, void *pContext){
Th_Free((Th_Interp *)pContext, (void *)pEntry);
}
/*
** Free a hash-table previously allocated by Th_HashNew().
*/
void Th_HashDelete(Th_Interp *interp, Th_Hash *pHash){
if( pHash ){
Th_HashIterate(interp, pHash, xFreeHashEntry, (void *)interp);
Th_Free(interp, pHash);
}
}
/*
** This function is used to insert or delete hash table items, or to
** query a hash table for an existing item.
**
** If parameter op is less than zero, then the hash-table element
** identified by (zKey, nKey) is removed from the hash-table if it
** exists. NULL is returned.
**
** Otherwise, if the hash-table contains an item with key (zKey, nKey),
** a pointer to the associated Th_HashEntry is returned. If parameter
** op is greater than zero, then a new entry is added if one cannot
** be found. If op is zero, then NULL is returned if the item is
** not already present in the hash-table.
*/
Th_HashEntry *Th_HashFind(
Th_Interp *interp,
Th_Hash *pHash,
const uchar *zKey,
int nKey,
int op /* -ve = delete, 0 = find, +ve = insert */
){
unsigned int iKey = 0;
int i;
Th_HashEntry *pRet;
Th_HashEntry **ppRet;
if( nKey<0 ){
nKey = th_strlen(zKey);
}
for(i=0; i<nKey; i++){
iKey = (iKey<<3) ^ iKey ^ zKey[i];
}
iKey = iKey % TH_HASHSIZE;
for(ppRet=&pHash->a[iKey]; (pRet=*ppRet); ppRet=&pRet->pNext){
assert( pRet && ppRet && *ppRet==pRet );
if( pRet->nKey==nKey && 0==memcmp(pRet->zKey, zKey, nKey) ) break;
}
if( op<0 && pRet ){
assert( ppRet && *ppRet==pRet );
*ppRet = pRet->pNext;
Th_Free(interp, pRet);
pRet = 0;
}
if( op>0 && !pRet ){
pRet = (Th_HashEntry *)Th_Malloc(interp, sizeof(Th_HashEntry) + nKey);
pRet->zKey = (uchar *)&pRet[1];
pRet->nKey = nKey;
memcpy(pRet->zKey, zKey, nKey);
pRet->pNext = pHash->a[iKey];
pHash->a[iKey] = pRet;
}
return pRet;
}
/*
** This function is the same as the standard strlen() function, except
** that it returns 0 (instead of being undefined) if the argument is
** a null pointer.
*/
int th_strlen(const unsigned char *zStr){
int n = 0;
if( zStr ){
while( zStr[n] ) n++;
}
return n;
}
/* Whitespace characters:
**
** ' ' 0x20
** '\t' 0x09
** '\n' 0x0A
** '\v' 0x0B
** '\f' 0x0C
** '\r' 0x0D
**
** Whitespace characters have the 0x01 flag set. Decimal digits have the
** 0x2 flag set. Single byte printable characters have the 0x4 flag set.
** Alphabet characters have the 0x8 bit set.
**
** The special list characters have the 0x10 flag set
**
** { } [ ] \ ; ' "
**
** " 0x22
**
*/
static unsigned char aCharProp[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, /* 0x0. */
0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x1. */
5, 4, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x2. */
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 20, 4, 4, 4, 4, /* 0x3. */
4, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, /* 0x4. */
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 20, 20, 20, 4, 4, /* 0x5. */
4, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, /* 0x6. */
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 20, 4, 20, 4, 4, /* 0x7. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x8. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x9. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xF. */
};
/*
** Clone of the standard isspace() and isdigit function/macros.
*/
int th_isspace(unsigned char c){
return (aCharProp[c] & 0x01);
}
int th_isdigit(unsigned char c){
return (aCharProp[c] & 0x02);
}
int th_isspecial(unsigned char c){
return (aCharProp[c] & 0x11);
}
int th_isalnum(unsigned char c){
return (aCharProp[c] & 0x0A);
}
#ifndef LONGDOUBLE_TYPE
# define LONGDOUBLE_TYPE long double
#endif
typedef uchar u8;
/*
** Return TRUE if z is a pure numeric string. Return FALSE if the
** string contains any character which is not part of a number. If
** the string is numeric and contains the '.' character, set *realnum
** to TRUE (otherwise FALSE).
**
** An empty string is considered non-numeric.
*/
static int sqlite3IsNumber(const char *z, int *realnum){
int incr = 1;
if( *z=='-' || *z=='+' ) z += incr;
if( !th_isdigit(*(u8*)z) ){
return 0;
}
z += incr;
if( realnum ) *realnum = 0;
while( th_isdigit(*(u8*)z) ){ z += incr; }
if( *z=='.' ){
z += incr;
if( !th_isdigit(*(u8*)z) ) return 0;
while( th_isdigit(*(u8*)z) ){ z += incr; }
if( realnum ) *realnum = 1;
}
if( *z=='e' || *z=='E' ){
z += incr;
if( *z=='+' || *z=='-' ) z += incr;
if( !th_isdigit(*(u8*)z) ) return 0;
while( th_isdigit(*(u8*)z) ){ z += incr; }
if( realnum ) *realnum = 1;
}
return *z==0;
}
/*
** The string z[] is an ascii representation of a real number.
** Convert this string to a double.
**
** This routine assumes that z[] really is a valid number. If it
** is not, the result is undefined.
**
** This routine is used instead of the library atof() function because
** the library atof() might want to use "," as the decimal point instead
** of "." depending on how locale is set. But that would cause problems
** for SQL. So this routine always uses "." regardless of locale.
*/
static int sqlite3AtoF(const char *z, double *pResult){
int sign = 1;
const char *zBegin = z;
LONGDOUBLE_TYPE v1 = 0.0;
while( th_isspace(*(u8*)z) ) z++;
if( *z=='-' ){
sign = -1;
z++;
}else if( *z=='+' ){
z++;
}
while( th_isdigit(*(u8*)z) ){
v1 = v1*10.0 + (*z - '0');
z++;
}
if( *z=='.' ){
LONGDOUBLE_TYPE divisor = 1.0;
z++;
while( th_isdigit(*(u8*)z) ){
v1 = v1*10.0 + (*z - '0');
divisor *= 10.0;
z++;
}
v1 /= divisor;
}
if( *z=='e' || *z=='E' ){
int esign = 1;
int eval = 0;
LONGDOUBLE_TYPE scale = 1.0;
z++;
if( *z=='-' ){
esign = -1;
z++;
}else if( *z=='+' ){
z++;
}
while( th_isdigit(*(u8*)z) ){
eval = eval*10 + *z - '0';
z++;
}
while( eval>=64 ){ scale *= 1.0e+64; eval -= 64; }
while( eval>=16 ){ scale *= 1.0e+16; eval -= 16; }
while( eval>=4 ){ scale *= 1.0e+4; eval -= 4; }
while( eval>=1 ){ scale *= 1.0e+1; eval -= 1; }
if( esign<0 ){
v1 /= scale;
}else{
v1 *= scale;
}
}
*pResult = sign<0 ? -v1 : v1;
return z - zBegin;
}
/*
** Try to convert the string passed as arguments (z, n) to an integer.
** If successful, store the result in *piOut and return TH_OK.
**
** If the string cannot be converted to an integer, return TH_ERROR.
** If the interp argument is not NULL, leave an error message in the
** interpreter result too.
*/
int Th_ToInt(Th_Interp *interp, const uchar *z, int n, int *piOut){
int i = 0;
int iOut = 0;
if( n<0 ){
n = th_strlen(z);
}
if( n>0 && (z[0]=='-' || z[0]=='+') ){
i = 1;
}
for(; i<n; i++){
if( !th_isdigit(z[i]) ){
Th_ErrorMessage(interp, "expected integer, got: \"", z, n);
return TH_ERROR;
}
iOut = iOut * 10 + (z[i] - 48);
}
if( n>0 && z[0]=='-' ){
iOut *= -1;
}
*piOut = iOut;
return TH_OK;
}
/*
** Try to convert the string passed as arguments (z, n) to a double.
** If successful, store the result in *pfOut and return TH_OK.
**
** If the string cannot be converted to a double, return TH_ERROR.
** If the interp argument is not NULL, leave an error message in the
** interpreter result too.
*/
int Th_ToDouble(
Th_Interp *interp,
const uchar *z,
int n,
double *pfOut
){
if( !sqlite3IsNumber((const char *)z, 0) ){
Th_ErrorMessage(interp, "expected number, got: \"", z, n);
return TH_ERROR;
}
sqlite3AtoF((const char *)z, pfOut);
return TH_OK;
}
/*
** Set the result of the interpreter to the th1 representation of
** the integer iVal and return TH_OK.
*/
int Th_SetResultInt(Th_Interp *interp, int iVal){
int isNegative = 0;
uchar zBuf[32];
uchar *z = &zBuf[32];
if( iVal<0 ){
isNegative = 1;
iVal = iVal * -1;
}
*(--z) = '\0';
*(--z) = (uchar)(48+(iVal%10));
while( (iVal = (iVal/10))>0 ){
*(--z) = (uchar)(48+(iVal%10));
assert(z>zBuf);
}
if( isNegative ){
*(--z) = '-';
}
return Th_SetResult(interp, z, -1);
}
/*
** Set the result of the interpreter to the th1 representation of
** the double fVal and return TH_OK.
*/
int Th_SetResultDouble(Th_Interp *interp, double fVal){
int i; /* Iterator variable */
double v = fVal; /* Input value */
uchar zBuf[128]; /* Output buffer */
uchar *z = zBuf; /* Output cursor */
int iDot = 0; /* Digit after which to place decimal point */
int iExp = 0; /* Exponent (NN in eNN) */
const uchar *zExp; /* String representation of iExp */
/* Precision: */
#define INSIGNIFICANT 0.000000000001
#define ROUNDER 0.0000000000005
double insignificant = INSIGNIFICANT;
/* If the real value is negative, write a '-' character to the
* output and transform v to the corresponding positive number.
*/
if( v<0.0 ){
*z++ = '-';
v *= -1.0;
}
/* Normalize v to a value between 1.0 and 10.0. Integer
* variable iExp is set to the exponent. i.e the original
* value is (v * 10^iExp) (or the negative thereof).
*/
if( v>0.0 ){
while( (v+ROUNDER)>=10.0 ) { iExp++; v *= 0.1; }
while( (v+ROUNDER)<1.0 ) { iExp--; v *= 10.0; }
}
v += ROUNDER;
/* For a small (<12) positive exponent, move the decimal point
* instead of using the "eXX" notation.
*/
if( iExp>0 && iExp<12 ){
iDot = iExp;
iExp = 0;
}
/* For a small (>-4) negative exponent, write leading zeroes
* instead of using the "eXX" notation.
*/
if( iExp<0 && iExp>-4 ){
*z++ = '0';
*z++ = '.';
for(i=0; i>(iExp+1); i--){
*z++ = '0';
}
iDot = -1;
iExp = 0;
}
/* Output the digits in real value v. The value of iDot determines
* where (if at all) the decimal point is placed.
*/
for(i=0; i<=(iDot+1) || v>=insignificant; i++){
*z++ = (uchar)(48 + (int)v);
v = (v - ((double)(int)v)) * 10.0;
insignificant *= 10.0;
if( iDot==i ){
*z++ = '.';
}
}
/* If the exponent is not zero, add the "eXX" notation to the
* end of the string.
*/
if( iExp!=0 ){
*z++ = 'e';
Th_SetResultInt(interp, iExp);
zExp = Th_GetResult(interp, 0);
for(i=0; zExp[i]; i++){
*z++ = zExp[i];
}
}
*z = '\0';
return Th_SetResult(interp, zBuf, -1);
}
/*
** Set the result of the interpreter to the th1 representation of
** the pointer p and return TH_OK. The th1 representation can be
** converted back to a pointer using Th_ToPtr().
*/
int Th_SetResultPtr(Th_Interp *interp, void *p){
char zBuf[32];
char *z;
int i;
unsigned int v = (unsigned int)p;
const char zHex[16] = "0123456789ABCDEF";
assert( sizeof(unsigned int)==sizeof(void *) );
zBuf[31] = '\0';
z = &zBuf[30];
for(i=0; i<(sizeof(unsigned int)*2); i++){
*z-- = zHex[(v&0x0000000F)];
v = v>>4;
}
*z-- = 'x';
*z = '0';
return Th_SetResult(interp, (uchar *)z, -1);
}
/*
** Convert input string (z, n) to a generic pointer. If the conversion
** is successful, store the result in *pp and return TH_OK.
**
** If the string cannot be converted to a pointer, return TH_ERROR.
** If the interp argument is not NULL, leave an error message in the
** interpreter result too.
*/
int Th_ToPtr(Th_Interp *interp, const uchar *z, int n, void **pp){
unsigned int iPtr;
int i;
assert(sizeof(unsigned int)==sizeof(void *));
if( n<3 || z[0]!='0' || z[1]!='x' ){
goto error_out;
}
iPtr = 0;
for(i=2; i<n; i++){
int digit = thHexdigit(z[i]);
if( digit<0 ){
goto error_out;
}
iPtr = (iPtr<<4) + digit;
}
*pp = (void *)iPtr;
return TH_OK;
error_out:
Th_ErrorMessage(interp, "expected pointer, got: \"", z, n);
return TH_ERROR;
}
|
Added src/th.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
/* This header file defines the external interface to the custom Scripting
** Language (TH) interpreter used to create test cases for SQLiteRT. The
** interpreted language and API are both based on Tcl.
*/
typedef unsigned char uchar;
/*
** Before creating an interpreter, the application must allocate and
** populate an instance of the following structure. It must remain valid
** for the lifetime of the interpreter.
*/
struct Th_Vtab {
void *(*xMalloc)(unsigned int);
void (*xFree)(void *);
};
typedef struct Th_Vtab Th_Vtab;
/*
** Opaque handle for interpeter.
*/
typedef struct Th_Interp Th_Interp;
/*
** Create and delete interpreters.
*/
Th_Interp * Th_CreateInterp(Th_Vtab *pVtab);
void Th_DeleteInterp(Th_Interp *);
/*
** Evaluate an TH program in the stack frame identified by parameter
** iFrame, according to the following rules:
**
** * If iFrame is 0, this means the current frame.
**
** * If iFrame is negative, then the nth frame up the stack, where n is
** the absolute value of iFrame. A value of -1 means the calling
** procedure.
**
** * If iFrame is +ve, then the nth frame from the bottom of the stack.
** An iFrame value of 1 means the toplevel (global) frame.
*/
int Th_Eval(Th_Interp *interp, int iFrame, const uchar *zProg, int nProg);
/*
** Evaluate a TH expression. The result is stored in the
** interpreter result.
*/
int Th_Expr(Th_Interp *interp, const uchar *, int);
/*
** Access TH variables in the current stack frame. If the variable name
** begins with "::", the lookup is in the top level (global) frame.
*/
int Th_GetVar(Th_Interp *, const uchar *, int);
int Th_SetVar(Th_Interp *, const uchar *, int, const uchar *, int);
int Th_LinkVar(Th_Interp *, const uchar *, int, int, const uchar *, int);
int Th_UnsetVar(Th_Interp *, const uchar *, int);
typedef int (*Th_CommandProc)(Th_Interp *, void *, int, const uchar **, int *);
/*
** Register new commands.
*/
int Th_CreateCommand(
Th_Interp *interp,
const char *zName,
/* int (*xProc)(Th_Interp *, void *, int, const uchar **, int *), */
Th_CommandProc xProc,
void *pContext,
void (*xDel)(Th_Interp *, void *)
);
/*
** Delete or rename commands.
*/
int Th_RenameCommand(Th_Interp *, const uchar *, int, const uchar *, int);
/*
** Push a new stack frame (local variable context) onto the interpreter
** stack, call the function supplied as parameter xCall with the two
** context arguments,
**
** xCall(interp, pContext1, pContext2)
**
** , then pop the frame off of the interpreter stack. The value returned
** by the xCall() function is returned as the result of this function.
**
** This is intended for use by the implementation of commands such as
** those created by [proc].
*/
int Th_InFrame(Th_Interp *interp,
int (*xCall)(Th_Interp *, void *pContext1, void *pContext2),
void *pContext1,
void *pContext2
);
/*
** Valid return codes for xProc callbacks.
*/
#define TH_OK 0
#define TH_ERROR 1
#define TH_BREAK 2
#define TH_RETURN 3
#define TH_CONTINUE 4
/*
** Set and get the interpreter result.
*/
int Th_SetResult(Th_Interp *, const uchar *, int);
const uchar *Th_GetResult(Th_Interp *, int *);
uchar *Th_TakeResult(Th_Interp *, int *);
/*
** Set an error message as the interpreter result. This also
** sets the global stack-trace variable $::th_stack_trace.
*/
int Th_ErrorMessage(Th_Interp *, const char *, const uchar *, int);
/*
** Access the memory management functions associated with the specified
** interpreter.
*/
void *Th_Malloc(Th_Interp *, int);
void Th_Free(Th_Interp *, void *);
/*
** Functions for handling TH lists.
*/
int Th_ListAppend(Th_Interp *, uchar **, int *, const uchar *, int);
int Th_SplitList(Th_Interp *, const uchar *, int, uchar ***, int **, int *);
int Th_StringAppend(Th_Interp *, uchar **, int *, const uchar *, int);
/*
** Functions for handling numbers and pointers.
*/
int Th_ToInt(Th_Interp *, const uchar *, int, int *);
int Th_ToDouble(Th_Interp *, const uchar *, int, double *);
int Th_ToPtr(Th_Interp *, const uchar *, int, void **);
int Th_SetResultInt(Th_Interp *, int);
int Th_SetResultDouble(Th_Interp *, double);
int Th_SetResultPtr(Th_Interp *, void *);
/*
** Drop in replacements for the corresponding standard library functions.
*/
int th_strlen(const unsigned char *);
int th_isdigit(unsigned char);
int th_isspace(unsigned char);
int th_isalnum(unsigned char);
int th_isspecial(unsigned char);
uchar *th_strdup(Th_Interp *interp, const uchar *z, int n);
/*
** Interfaces to register the language extensions.
*/
int th_register_language(Th_Interp *interp); /* th_lang.c */
int th_register_sqlite(Th_Interp *interp); /* th_sqlite.c */
int th_register_vfs(Th_Interp *interp); /* th_vfs.c */
int th_register_testvfs(Th_Interp *interp); /* th_testvfs.c */
/*
** General purpose hash table from th_lang.c.
*/
typedef struct Th_Hash Th_Hash;
typedef struct Th_HashEntry Th_HashEntry;
struct Th_HashEntry {
void *pData;
uchar *zKey;
int nKey;
Th_HashEntry *pNext; /* Internal use only */
};
Th_Hash *Th_HashNew(Th_Interp *);
void Th_HashDelete(Th_Interp *, Th_Hash *);
void Th_HashIterate(Th_Interp*,Th_Hash*,void (*x)(Th_HashEntry*, void*),void*);
Th_HashEntry *Th_HashFind(Th_Interp*, Th_Hash*, const uchar*, int, int);
/*
** Useful functions from th_lang.c.
*/
int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg);
typedef struct Th_SubCommand {char *zName; Th_CommandProc xProc;} Th_SubCommand;
int Th_CallSubCommand(Th_Interp*,void*,int,const uchar**,int*,Th_SubCommand*);
|
Added src/th_lang.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 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 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 |
/*
** This file contains the implementation of all of the TH language
** built-in commands.
**
** All built-in commands are implemented using the public interface
** declared in th.h, so this file serves as both a part of the language
** implementation and an example of how to extend the language with
** new commands.
*/
#include "th.h"
#include <string.h>
#include <assert.h>
int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg){
Th_ErrorMessage(interp,
"wrong # args: should be \"", (const uchar*)zMsg, -1
);
return TH_ERROR;
}
/*
** Syntax:
**
** catch script ?varname?
*/
static int catch_command(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl
){
int rc;
if( argc!=2 && argc!=3 ){
return Th_WrongNumArgs(interp, "catch script ?varname?");
}
rc = Th_Eval(interp, 0, argv[1], -1);
if( argc==3 ){
int nResult;
const uchar *zResult = Th_GetResult(interp, &nResult);
Th_SetVar(interp, argv[2], argl[2], zResult, nResult);
}
Th_SetResultInt(interp, rc);
return TH_OK;
}
/*
** TH Syntax:
**
** if expr1 body1 ?elseif expr2 body2? ? ?else? bodyN?
*/
static int if_command(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl
){
int rc = TH_OK;
int iCond; /* Result of evaluating expression */
int i;
const uchar *zResult;
int nResult;
if( argc<3 ){
goto wrong_args;
}
for(i=0; i<argc && rc==TH_OK; i+=3){
if( i>argc-3 ){
i = argc-3;
iCond = 1;
}else{
if( TH_OK!=Th_Expr(interp, argv[i+1], argl[i+1]) ){
return TH_ERROR;
}
zResult = Th_GetResult(interp, &nResult);
rc = Th_ToInt(interp, zResult, nResult, &iCond);
}
if( iCond && rc==TH_OK ){
rc = Th_Eval(interp, 0, argv[i+2], -1);
break;
}
}
return rc;
wrong_args:
return Th_WrongNumArgs(interp, "if ...");
}
/*
** TH Syntax:
**
** expr expr
*/
static int expr_command(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl
){
if( argc!=2 ){
return Th_WrongNumArgs(interp, "expr expression");
}
return Th_Expr(interp, argv[1], argl[1]);
}
/*
** Evaluate the th1 script (zBody, nBody) in the local stack frame.
** Return the result of the evaluation, except if the result
** is TH_CONTINUE, return TH_OK instead.
*/
static int eval_loopbody(Th_Interp *interp, const uchar *zBody, int nBody){
int rc = Th_Eval(interp, 0, zBody, nBody);
if( rc==TH_CONTINUE ){
rc = TH_OK;
}
return rc;
}
/*
** TH Syntax:
**
** for init condition incr script
*/
static int for_command(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl
){
int rc;
int iCond;
if( argc!=5 ){
return Th_WrongNumArgs(interp, "for init condition incr script");
}
/* Evaluate the 'init' script */
rc = Th_Eval(interp, 0, argv[1], -1);
while( rc==TH_OK
&& TH_OK==(rc = Th_Expr(interp, argv[2], -1))
&& TH_OK==(rc = Th_ToInt(interp, Th_GetResult(interp, 0), -1, &iCond))
&& iCond
&& TH_OK==(rc = eval_loopbody(interp, argv[4], argl[4]))
){
rc = Th_Eval(interp, 0, argv[3], -1);
}
if( rc==TH_BREAK ) rc = TH_OK;
return rc;
}
/*
** TH Syntax:
**
** list ?arg1 ?arg2? ...?
*/
static int list_command(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl
){
uchar *zList = 0;
int nList = 0;
int i;
for(i=1; i<argc; i++){
Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]);
}
Th_SetResult(interp, zList, nList);
Th_Free(interp, zList);
return TH_OK;
}
/*
** TH Syntax:
**
** lindex list index
*/
static int lindex_command(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl
){
int iElem;
int rc;
uchar **azElem;
int *anElem;
int nCount;
if( argc!=3 ){
return Th_WrongNumArgs(interp, "lindex list index");
}
if( TH_OK!=Th_ToInt(interp, argv[2], argl[2], &iElem) ){
return TH_ERROR;
}
rc = Th_SplitList(interp, argv[1], argl[1], &azElem, &anElem, &nCount);
if( rc==TH_OK ){
if( iElem<nCount && iElem>=0 ){
Th_SetResult(interp, azElem[iElem], anElem[iElem]);
}else{
Th_SetResult(interp, 0, 0);
}
Th_Free(interp, azElem);
}
return rc;
}
/*
** TH Syntax:
**
** llength list
*/
static int llength_command(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl
){
int nElem;
int rc;
if( argc!=2 ){
return Th_WrongNumArgs(interp, "llength list");
}
rc = Th_SplitList(interp, argv[1], argl[1], 0, 0, &nElem);
if( rc==TH_OK ){
Th_SetResultInt(interp, nElem);
}
return rc;
}
/*
** TH Syntax:
**
** set varname ?value?
*/
static int set_command(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl
){
if( argc!=2 && argc!=3 ){
return Th_WrongNumArgs(interp, "set varname ?value?");
}
if( argc==3 ){
Th_SetVar(interp, argv[1], argl[1], argv[2], argl[2]);
}
return Th_GetVar(interp, argv[1], argl[1]);
}
/*
** When a new command is created using the built-in [proc] command, an
** instance of the following structure is allocated and populated. A
** pointer to the structure is passed as the context (second) argument
** to function proc_call1() when the new command is executed.
*/
typedef struct ProcDefn ProcDefn;
struct ProcDefn {
int nParam; /* Number of formal (non "args") parameters */
uchar **azParam; /* Parameter names */
int *anParam; /* Lengths of parameter names */
uchar **azDefault; /* Default values */
int *anDefault; /* Lengths of default values */
int hasArgs; /* True if there is an "args" parameter */
uchar *zProgram; /* Body of proc */
int nProgram; /* Number of bytes at zProgram */
uchar *zUsage; /* Usage message */
int nUsage; /* Number of bytes at zUsage */
};
/* This structure is used to temporarily store arguments passed to an
** invocation of a command created using [proc]. A pointer to an
** instance is passed as the second argument to the proc_call2() function.
*/
typedef struct ProcArgs ProcArgs;
struct ProcArgs {
int argc;
const uchar **argv;
int *argl;
};
/*
** Each time a command created using [proc] is invoked, a new
** th1 stack frame is allocated (for the proc's local variables) and
** this function invoked.
**
** Argument pContext1 points to the associated ProcDefn structure.
** Argument pContext2 points to a ProcArgs structure that contains
** the arguments passed to this specific invocation of the proc.
*/
static int proc_call2(Th_Interp *interp, void *pContext1, void *pContext2){
int i;
ProcDefn *p = (ProcDefn *)pContext1;
ProcArgs *pArgs = (ProcArgs *)pContext2;
/* Check if there are the right number of arguments. If there are
** not, generate a usage message for the command.
*/
if( (pArgs->argc>(p->nParam+1) && !p->hasArgs)
|| (pArgs->argc<=(p->nParam) && !p->azDefault[pArgs->argc-1])
){
uchar *zUsage = 0;
int nUsage = 0;
Th_StringAppend(interp, &zUsage, &nUsage, pArgs->argv[0], pArgs->argl[0]);
Th_StringAppend(interp, &zUsage, &nUsage, p->zUsage, p->nUsage);
Th_StringAppend(interp, &zUsage, &nUsage, (const uchar *)"", 1);
Th_WrongNumArgs(interp, zUsage);
Th_Free(interp, zUsage);
return TH_ERROR;
}
/* Populate the formal proc parameters. */
for(i=0; i<p->nParam; i++){
const uchar *zVal;
int nVal;
if( pArgs->argc>(i+1) ){
zVal = pArgs->argv[i+1];
nVal = pArgs->argl[i+1];
}else{
zVal = p->azDefault[i];
nVal = p->anDefault[i];
}
Th_SetVar(interp, p->azParam[i], p->anParam[i], zVal, nVal);
}
/* Populate the "args" parameter, if it exists */
if( p->hasArgs ){
uchar *zArgs = 0;
int nArgs = 0;
for(i=p->nParam+1; i<pArgs->argc; i++){
Th_ListAppend(interp, &zArgs, &nArgs, pArgs->argv[i], pArgs->argl[i]);
}
Th_SetVar(interp, (const uchar *)"args", -1, zArgs, nArgs);
}
Th_SetResult(interp, 0, 0);
return Th_Eval(interp, 0, p->zProgram, p->nProgram);
}
/*
** This function is the command callback registered for all commands
** created using the [proc] command. The second argument, pContext,
** is a pointer to the associated ProcDefn structure.
*/
static int proc_call1(
Th_Interp *interp,
void *pContext,
int argc,
const uchar **argv,
int *argl
){
int rc;
ProcDefn *p = (ProcDefn *)pContext;
ProcArgs procargs;
/* Call function proc_call2(), which will call Th_Eval() to evaluate
** the body of the [proc], in a new Th stack frame. This is so that
** the proc body has its own local variable context.
*/
procargs.argc = argc;
procargs.argv = argv;
procargs.argl = argl;
rc = Th_InFrame(interp, proc_call2, (void *)p, (void *)&procargs);
if( rc==TH_RETURN ){
rc = TH_OK;
}
return rc;
}
/*
** This function is registered as the delete callback for all commands
** created using the built-in [proc] command. It is called automatically
** when a command created using [proc] is deleted.
**
** It frees the ProcDefn structure allocated when the command was created.
*/
static void proc_del(Th_Interp *interp, void *pContext){
ProcDefn *p = (ProcDefn *)pContext;
Th_Free(interp, (void *)p->zUsage);
Th_Free(interp, (void *)p);
}
/*
** TH Syntax:
**
** proc name arglist code
*/
static int proc_command(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl
){
int rc;
char *zName;
ProcDefn *p;
int nByte;
int i;
uchar *zSpace;
uchar **azParam;
int *anParam;
int nParam;
uchar *zUsage = 0; /* Build up a usage message here */
int nUsage = 0; /* Number of bytes at zUsage */
if( argc!=4 ){
return Th_WrongNumArgs(interp, "proc name arglist code");
}
if( Th_SplitList(interp, argv[2], argl[2], &azParam, &anParam, &nParam) ){
return TH_ERROR;
}
/* Allocate the new ProcDefn structure. */
nByte = sizeof(ProcDefn) + /* ProcDefn structure */
(sizeof(uchar *) + sizeof(int)) * nParam + /* azParam, anParam */
(sizeof(uchar *) + sizeof(int)) * nParam + /* azDefault, anDefault */
argl[3] + /* zProgram */
argl[2]; /* Space for copies of parameter names and default values */
p = (ProcDefn *)Th_Malloc(interp, nByte);
/* If the last parameter in the parameter list is "args", then set the
** ProcDefn.hasArgs flag. The "args" parameter does not require an
** entry in the ProcDefn.azParam[] or ProcDefn.azDefault[] arrays.
*/
if( anParam[nParam-1]==4 && 0==memcmp(azParam[nParam-1], "args", 4) ){
p->hasArgs = 1;
nParam--;
}
p->nParam = nParam;
p->azParam = (uchar **)&p[1];
p->anParam = (int *)&p->azParam[nParam];
p->azDefault = (uchar **)&p->anParam[nParam];
p->anDefault = (int *)&p->azDefault[nParam];
p->zProgram = (uchar *)&p->anDefault[nParam];
memcpy(p->zProgram, argv[3], argl[3]);
p->nProgram = argl[3];
zSpace = &p->zProgram[p->nProgram];
for(i=0; i<nParam; i++){
uchar **az;
int *an;
int n;
if( Th_SplitList(interp, azParam[i], anParam[i], &az, &an, &n) ){
goto error_out;
}
if( n<1 || n>2 ){
const char expected[] = "expected parameter, got \"";
Th_ErrorMessage(interp, expected, azParam[i], anParam[i]);
Th_Free(interp, az);
goto error_out;
}
p->anParam[i] = an[0];
p->azParam[i] = zSpace;
memcpy(zSpace, az[0], an[0]);
zSpace += an[0];
if( n==2 ){
p->anDefault[i] = an[1];
p->azDefault[i] = zSpace;
memcpy(zSpace, az[1], an[1]);
zSpace += an[1];
}
Th_StringAppend(interp, &zUsage, &nUsage, (const uchar *)" ", 1);
if( n==2 ){
Th_StringAppend(interp, &zUsage, &nUsage, (const uchar *)"?", 1);
Th_StringAppend(interp, &zUsage, &nUsage, az[0], an[0]);
Th_StringAppend(interp, &zUsage, &nUsage, (const uchar *)"?", 1);
}else{
Th_StringAppend(interp, &zUsage, &nUsage, az[0], an[0]);
}
Th_Free(interp, az);
}
assert( zSpace-(uchar *)p<=nByte );
/* If there is an "args" parameter, append it to the end of the usage
** message. Set ProcDefn.zUsage to point at the usage message. It will
** be freed along with the rest of the proc-definition by proc_del().
*/
if( p->hasArgs ){
Th_StringAppend(interp, &zUsage, &nUsage, (const uchar *)" ?args...?", -1);
}
p->zUsage = zUsage;
p->nUsage = nUsage;
/* Register the new command with the th1 interpreter. */
zName = (char *)argv[1];
rc = Th_CreateCommand(interp, zName, proc_call1, (void *)p, proc_del);
if( rc==TH_OK ){
Th_SetResult(interp, 0, 0);
}
Th_Free(interp, azParam);
return TH_OK;
error_out:
Th_Free(interp, azParam);
Th_Free(interp, zUsage);
return TH_ERROR;
}
/*
** TH Syntax:
**
** rename oldcmd newcmd
*/
static int rename_command(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl
){
if( argc!=3 ){
return Th_WrongNumArgs(interp, "rename oldcmd newcmd");
}
return Th_RenameCommand(interp, argv[1], argl[1], argv[2], argl[2]);
}
/*
** TH Syntax:
**
** break ?value...?
** continue ?value...?
** ok ?value...?
** error ?value...?
*/
static int simple_command(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl
){
if( argc!=1 && argc!=2 ){
return Th_WrongNumArgs(interp, "return ?value?");
}
if( argc==2 ){
Th_SetResult(interp, argv[1], argl[1]);
}
return (int)ctx;
}
/*
** TH Syntax:
**
** return ?-code code? ?value?
*/
static int return_command(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl
){
int iCode = TH_RETURN;
if( argc<1 || argc>4 ){
return Th_WrongNumArgs(interp, "return ?-code code? ?value?");
}
if( argc>2 ){
int rc = Th_ToInt(interp, argv[2], argl[2], &iCode);
if( rc!=TH_OK ){
return rc;
}
}
if( argc==2 || argc==4 ){
Th_SetResult(interp, argv[argc-1], argl[argc-1]);
}
return iCode;
}
/*
** TH Syntax:
**
** string compare STRING1 STRING2
*/
static int string_compare_command(
Th_Interp *interp, void *ctx, int argc, const uchar **argv, int *argl
){
const uchar *zRight; int nRight;
const uchar *zLeft; int nLeft;
int i;
int iRes = 0;
if( argc!=4 ){
return Th_WrongNumArgs(interp, "string compare str1 str2");
}
zLeft = argv[2];
nLeft = argl[2];
zRight = argv[3];
nRight = argl[3];
for(i=0; iRes==0 && i<nLeft && i<nRight; i++){
iRes = zLeft[i]-zRight[i];
}
if( iRes==0 ){
iRes = nLeft-nRight;
}
if( iRes<0 ) iRes = -1;
if( iRes>0 ) iRes = 1;
return Th_SetResultInt(interp, iRes);
}
/*
** TH Syntax:
**
** string first NEEDLE HAYSTACK
*/
static int string_first_command(
Th_Interp *interp, void *ctx, int argc, const uchar **argv, int *argl
){
const uchar *zNeedle;
int nNeedle;
const uchar *zHaystack;
int nHaystack;
int i;
int iRes;
if( argc!=4 ){
return Th_WrongNumArgs(interp, "string first needle haystack");
}
zNeedle = argv[2];
nNeedle = argl[2];
zHaystack = argv[3];
nHaystack = argl[3];
for(i=0; i<(nHaystack-nNeedle); i++){
if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){
iRes = i;
break;
}
}
return Th_SetResultInt(interp, iRes);
}
/*
** TH Syntax:
**
** string is CLASS STRING
*/
static int string_is_command(
Th_Interp *interp, void *ctx, int argc, const uchar **argv, int *argl
){
int i;
int iRes = 1;
if( argc!=4 ){
return Th_WrongNumArgs(interp, "string is class string");
}
if( argl[2]!=5 || 0!=memcmp(argv[2], "alnum", 5) ){
Th_ErrorMessage(interp, "Expected alnum, got: ", argv[2], argl[2]);
return TH_ERROR;
}
for(i=0; i<argl[3]; i++){
if( !th_isalnum(argv[3][i]) ){
iRes = 0;
}
}
return Th_SetResultInt(interp, iRes);
}
/*
** TH Syntax:
**
** string last NEEDLE HAYSTACK
*/
static int string_last_command(
Th_Interp *interp, void *ctx, int argc, const uchar **argv, int *argl
){
const uchar *zNeedle;
int nNeedle;
const uchar *zHaystack;
int nHaystack;
int i;
int iRes;
if( argc!=4 ){
return Th_WrongNumArgs(interp, "string first needle haystack");
}
zNeedle = argv[2];
nNeedle = argl[2];
zHaystack = argv[3];
nHaystack = argl[3];
for(i=nHaystack-nNeedle-1; i>=0; i--){
if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){
iRes = i;
break;
}
}
return Th_SetResultInt(interp, iRes);
}
/*
** TH Syntax:
**
** string length STRING
*/
static int string_length_command(
Th_Interp *interp, void *ctx, int argc, const uchar **argv, int *argl
){
if( argc!=3 ){
return Th_WrongNumArgs(interp, "string length string");
}
return Th_SetResultInt(interp, argl[2]);
}
/*
** TH Syntax:
**
** string range STRING FIRST LAST
*/
static int string_range_command(
Th_Interp *interp, void *ctx, int argc, const uchar **argv, int *argl
){
int iStart;
int iEnd;
if( argc!=5 ){
return Th_WrongNumArgs(interp, "string range string first last");
}
if( argl[4]==3 && 0==memcmp("end", argv[4], 3) ){
iEnd = argl[2];
}else if( Th_ToInt(interp, argv[4], argl[4], &iEnd) ){
Th_ErrorMessage(
interp, "Expected \"end\" or integer, got:", argv[4], argl[4]);
return TH_ERROR;
}
if( Th_ToInt(interp, argv[3], argl[3], &iStart) ){
return TH_ERROR;
}
if( iStart<0 ) iStart = 0;
if( iEnd>=argl[2] ) iEnd = argl[2]-1;
if( iStart>iEnd ) iEnd = iStart-1;
return Th_SetResult(interp, &argv[2][iStart], iEnd-iStart+1);
}
/*
** TH Syntax:
**
** string repeat STRING COUNT
*/
static int string_repeat_command(
Th_Interp *interp, void *ctx, int argc, const uchar **argv, int *argl
){
int n;
int i;
int nByte;
uchar *zByte;
if( argc!=4 ){
return Th_WrongNumArgs(interp, "string repeat string n");
}
if( Th_ToInt(interp, argv[3], argl[3], &n) ){
return TH_ERROR;
}
nByte = argl[2] * n;
zByte = Th_Malloc(interp, nByte+1);
for(i=0; i<nByte; i+=argl[2]){
memcpy(&zByte[i], argv[2], argl[2]);
}
Th_SetResult(interp, zByte, nByte);
Th_Free(interp, zByte);
return TH_OK;
}
/*
** TH Syntax:
**
** info exists VAR
*/
static int info_exists_command(
Th_Interp *interp, void *ctx, int argc, const uchar **argv, int *argl
){
int rc;
if( argc!=3 ){
return Th_WrongNumArgs(interp, "info exists var");
}
rc = Th_GetVar(interp, argv[2], argl[2]);
Th_SetResultInt(interp, rc?0:1);
return TH_OK;
}
/*
** TH Syntax:
**
** unset VAR
*/
static int unset_command(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl
){
if( argc!=2 ){
return Th_WrongNumArgs(interp, "unset var");
}
return Th_UnsetVar(interp, argv[1], argl[1]);
}
int Th_CallSubCommand(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl,
Th_SubCommand *aSub
){
int i;
for(i=0; aSub[i].zName; i++){
uchar *zName = (uchar *)aSub[i].zName;
if( th_strlen(zName)==argl[1] && 0==memcmp(zName, argv[1], argl[1]) ){
return aSub[i].xProc(interp, ctx, argc, argv, argl);
}
}
Th_ErrorMessage(interp, "Expected sub-command, got:", argv[1], argl[1]);
return TH_ERROR;
}
/*
** TH Syntax:
**
** string compare STR1 STR2
** string first NEEDLE HAYSTACK ?STARTINDEX?
** string is CLASS STRING
** string last NEEDLE HAYSTACK ?STARTINDEX?
** string length STRING
** string range STRING FIRST LAST
** string repeat STRING COUNT
*/
static int string_command(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl
){
Th_SubCommand aSub[] = {
{ "compare", string_compare_command },
{ "first", string_first_command },
{ "is", string_is_command },
{ "last", string_last_command },
{ "length", string_length_command },
{ "range", string_range_command },
{ "repeat", string_repeat_command },
{ 0, 0 }
};
return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub);
}
/*
** TH Syntax:
**
** info exists VARNAME
*/
static int info_command(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl
){
Th_SubCommand aSub[] = {
{ "exists", info_exists_command },
{ 0, 0 }
};
return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub);
}
/*
** Convert the script level frame specification (used by the commands
** [uplevel] and [upvar]) in (zFrame, nFrame) to an integer frame as
** used by Th_LinkVar() and Th_Eval(). If successful, write the integer
** frame level to *piFrame and return TH_OK. Otherwise, return TH_ERROR
** and leave an error message in the interpreter result.
*/
static int thToFrame(
Th_Interp *interp,
const uchar *zFrame,
int nFrame,
int *piFrame
){
int iFrame;
if( th_isdigit(zFrame[0]) ){
int rc = Th_ToInt(interp, zFrame, nFrame, &iFrame);
if( rc!=TH_OK ) return rc;
iFrame = iFrame * -1;
}else if( zFrame[0]=='#' ){
int rc = Th_ToInt(interp, &zFrame[1], nFrame-1, &iFrame);
if( rc!=TH_OK ) return rc;
iFrame = iFrame + 1;
}else{
return TH_ERROR;
}
*piFrame = iFrame;
return TH_OK;
}
/*
** TH Syntax:
**
** uplevel ?LEVEL? SCRIPT
*/
static int uplevel_command(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl
){
int iFrame = -1;
if( argc!=2 && argc!=3 ){
return Th_WrongNumArgs(interp, "uplevel ?level? script...");
}
if( argc==3 && TH_OK!=thToFrame(interp, argv[1], argl[1], &iFrame) ){
return TH_ERROR;
}
return Th_Eval(interp, iFrame, argv[argc-1], -1);
}
/*
** TH Syntax:
**
** upvar ?FRAME? OTHERVAR MYVAR ?OTHERVAR MYVAR ...?
*/
static int upvar_command(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl
){
int iVar = 1;
int iFrame = -1;
int rc = TH_OK;
int i;
if( TH_OK==thToFrame(0, argv[1], argl[1], &iFrame) ){
iVar++;
}
if( argc==iVar || (argc-iVar)%2 ){
return Th_WrongNumArgs(interp,
"upvar frame othervar myvar ?othervar myvar...?");
}
for(i=iVar; rc==TH_OK && i<argc; i=i+2){
rc = Th_LinkVar(interp, argv[i+1], argl[i+1], iFrame, argv[i], argl[i]);
}
return rc;
}
/*
** TH Syntax:
**
** breakpoint ARGS
**
** This command does nothing at all. Its purpose in life is to serve
** as a point for setting breakpoints in a debugger.
*/
static int breakpoint_command(
Th_Interp *interp,
void *ctx,
int argc,
const uchar **argv,
int *argl
){
int cnt = 0;
cnt++;
return TH_OK;
}
/*
** Register the built-in th1 language commands with interpreter interp.
** Usually this is called soon after interpreter creation.
*/
int th_register_language(Th_Interp *interp){
/* Array of built-in commands. */
struct _Command {
const char *zName;
Th_CommandProc xProc;
void *pContext;
} aCommand[] = {
{"catch", catch_command, 0},
{"expr", expr_command, 0},
{"for", for_command, 0},
{"if", if_command, 0},
{"info", info_command, 0},
{"lindex", lindex_command, 0},
{"list", list_command, 0},
{"llength", llength_command, 0},
{"proc", proc_command, 0},
{"rename", rename_command, 0},
{"set", set_command, 0},
{"string", string_command, 0},
{"unset", unset_command, 0},
{"uplevel", uplevel_command, 0},
{"upvar", upvar_command, 0},
{"breakpoint", breakpoint_command, 0},
{"return", return_command, 0},
{"break", simple_command, (void *)TH_BREAK},
{"continue", simple_command, (void *)TH_CONTINUE},
{"error", simple_command, (void *)TH_ERROR},
{0, 0}
};
int i;
/* Add the language commands. */
for(i=0; i<(sizeof(aCommand)/sizeof(aCommand[0])); i++){
void *ctx = aCommand[i].pContext;
Th_CreateCommand(interp, aCommand[i].zName, aCommand[i].xProc, ctx, 0);
}
return TH_OK;
}
|
Added src/th_main.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 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 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 |
/*
** Copyright (c) 2008 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License version 2 as published by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA 02111-1307, USA.
**
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains an interface between the TH scripting language
** (an independent project) and fossil.
*/
#include "config.h"
#include "th_main.h"
/*
** Global variable counting the number of outstanding calls to malloc()
** made by the th1 implementation. This is used to catch memory leaks
** in the interpreter. Obviously, it also means th1 is not threadsafe.
*/
static int nOutstandingMalloc = 0;
/*
** Implementations of malloc() and free() to pass to the interpreter.
*/
static void *xMalloc(unsigned int n){
void *p = malloc(n);
if( p ){
nOutstandingMalloc++;
}
return p;
}
static void xFree(void *p){
if( p ){
nOutstandingMalloc--;
}
free(p);
}
static Th_Vtab vtab = { xMalloc, xFree };
/*
** True if output is enabled. False if disabled.
*/
static int enableOutput = 1;
/*
** TH command: enable_output BOOLEAN
**
** Enable or disable the puts and hputs commands.
*/
static int enableOutputCmd(
Th_Interp *interp,
void *p,
int argc,
const unsigned char **argv,
int *argl
){
if( argc!=2 ){
return Th_WrongNumArgs(interp, "enable_output BOOLEAN");
}
return Th_ToInt(interp, argv[1], argl[1], &enableOutput);
}
/*
** Send text to the appropriate output: Either to the console
** or to the CGI reply buffer.
*/
static void sendText(const char *z, int n, int encode){
if( enableOutput && n ){
if( n<0 ) n = strlen(z);
if( encode ){
z = htmlize(z, n);
n = strlen(z);
}
if( g.cgiPanic ){
cgi_append_content(z, n);
}else{
fwrite(z, 1, n, stdout);
}
if( encode ) free((char*)z);
}
}
/*
** TH command: puts STRING
** TH command: html STRING
**
** Output STRING as HTML (html) or unchanged (puts).
*/
static int putsCmd(
Th_Interp *interp,
void *pConvert,
int argc,
const unsigned char **argv,
int *argl
){
if( argc!=2 ){
return Th_WrongNumArgs(interp, "puts STRING");
}
sendText((char*)argv[1], argl[1], pConvert!=0);
return TH_OK;
}
/*
** TH command: wiki STRING
**
** Render the input string as wiki.
*/
static int wikiCmd(
Th_Interp *interp,
void *p,
int argc,
const unsigned char **argv,
int *argl
){
if( argc!=2 ){
return Th_WrongNumArgs(interp, "wiki STRING");
}
if( enableOutput ){
Blob src;
blob_init(&src, (char*)argv[1], argl[1]);
wiki_convert(&src, 0, WIKI_INLINE);
blob_reset(&src);
}
return TH_OK;
}
/*
** TH command: hascap STRING
**
** Return true if the user has all of the capabilities listed in STRING.
*/
static int hascapCmd(
Th_Interp *interp,
void *p,
int argc,
const unsigned char **argv,
int *argl
){
if( argc!=2 ){
return Th_WrongNumArgs(interp, "hascap STRING");
}
Th_SetResultInt(interp, login_has_capability((char*)argv[1],argl[1]));
return TH_OK;
}
/*
** TH1 command: combobox NAME TEXT-LIST NUMLINES
**
** Generate an HTML combobox. NAME is both the name of the
** CGI parameter and the name of a variable that contains the
** currently selected value. TEXT-LIST is a list of possible
** values for the combobox. NUMLINES is 1 for a true combobox.
** If NUMLINES is greater than one then the display is a listbox
** with the number of lines given.
*/
static int comboboxCmd(
Th_Interp *interp,
void *p,
int argc,
const unsigned char **argv,
int *argl
){
if( argc!=4 ){
return Th_WrongNumArgs(interp, "combobox NAME TEXT-LIST NUMLINES");
}
if( enableOutput ){
int height;
Blob list, elem, name;
int nValue;
const char *zValue;
char *z, *zH;
if( Th_ToInt(interp, argv[3], argl[3], &height) ) return TH_ERROR;
blob_init(&list, (char*)argv[2], argl[2]);
blob_init(&name, (char*)argv[1], argl[1]);
zValue = Th_Fetch(blob_str(&name), &nValue);
z = mprintf("<select name=\"%z\" size=\"%d\">",
htmlize(blob_buffer(&name), blob_size(&name)), height);
sendText(z, -1, 0);
free(z);
blob_reset(&name);
while( blob_token(&list, &elem) ){
zH = htmlize(blob_buffer(&elem), blob_size(&elem));
if( zValue && blob_size(&elem)==nValue
&& memcmp(zValue, blob_buffer(&elem), nValue)==0 ){
z = mprintf("<option value=\"%s\" selected>%s</option>", zH, zH);
}else{
z = mprintf("<option value=\"%s\">%s</option>", zH, zH);
}
free(zH);
sendText(z, -1, 0);
free(z);
}
sendText("</select>", -1, 0);
blob_reset(&list);
}
return TH_OK;
}
/*
** TH1 command: linecount STRING MAX MIN
**
** Return one more than the number of \n characters in STRING. But
** never return less than MIN or more than MAX.
*/
static int linecntCmd(
Th_Interp *interp,
void *p,
int argc,
const unsigned char **argv,
int *argl
){
const uchar *z;
int size, n, i;
int iMin, iMax;
if( argc!=4 ){
return Th_WrongNumArgs(interp, "linecount STRING MAX MIN");
}
if( Th_ToInt(interp, argv[2], argl[2], &iMax) ) return TH_ERROR;
if( Th_ToInt(interp, argv[3], argl[3], &iMin) ) return TH_ERROR;
z = argv[1];
size = argl[1];
for(n=1, i=0; i<size; i++){
if( z[i]=='\n' ){
n++;
if( n>=iMax ) break;
}
}
if( n<iMin ) n = iMin;
if( n>iMax ) n = iMax;
Th_SetResultInt(interp, n);
return TH_OK;
}
/*
** Make sure the interpreter has been initialized.
*/
void Th_FossilInit(void){
static struct _Command {
const char *zName;
Th_CommandProc xProc;
void *pContext;
} aCommand[] = {
{"combobox", comboboxCmd, 0},
{"enable_output", enableOutputCmd, 0},
{"linecount", linecntCmd, 0},
{"hascap", hascapCmd, 0},
{"html", putsCmd, 0},
{"puts", putsCmd, (void*)1},
{"wiki", wikiCmd, 0},
};
if( g.interp==0 ){
int i;
g.interp = Th_CreateInterp(&vtab);
th_register_language(g.interp); /* Basic scripting commands. */
for(i=0; i<sizeof(aCommand)/sizeof(aCommand[0]); i++){
Th_CreateCommand(g.interp, aCommand[i].zName, aCommand[i].xProc,
aCommand[i].pContext, 0);
}
}
}
/*
** Store a string value in a variable in the interpreter.
*/
void Th_Store(const char *zName, const char *zValue){
Th_FossilInit();
Th_SetVar(g.interp, (uchar*)zName, -1, (uchar*)zValue, strlen(zValue));
}
/*
** Retrieve a string value from the interpreter. If no such
** variable exists, return NULL.
*/
char *Th_Fetch(const char *zName, int *pSize){
int rc;
Th_FossilInit();
rc = Th_GetVar(g.interp, (uchar*)zName, -1);
if( rc==TH_OK ){
return (char*)Th_GetResult(g.interp, pSize);
}else{
return 0;
}
}
/*
** Return true if the string begins with the TH1 begin-script
** tag: <th1>.
*/
static int isBeginScriptTag(const char *z){
return z[0]=='<'
&& (z[1]=='t' || z[1]=='T')
&& (z[2]=='h' || z[2]=='H')
&& z[3]=='1'
&& z[4]=='>';
}
/*
** Return true if the string begins with the TH1 end-script
** tag: </th1>.
*/
static int isEndScriptTag(const char *z){
return z[0]=='<'
&& z[1]=='/'
&& (z[2]=='t' || z[2]=='T')
&& (z[3]=='h' || z[3]=='H')
&& z[4]=='1'
&& z[5]=='>';
}
/*
** If string z[0...] contains a valid variable name, return
** the number of characters in that name. Otherwise, return 0.
*/
static int validVarName(const char *z){
int i = 0;
int inBracket = 0;
if( z[0]=='<' ){
inBracket = 1;
z++;
}
if( z[0]==':' && z[1]==':' && isalpha(z[2]) ){
z += 3;
i += 3;
}else if( isalpha(z[0]) ){
z ++;
i += 1;
}else{
return 0;
}
while( isalnum(z[0]) || z[0]=='_' ){
z++;
i++;
}
if( inBracket ){
if( z[0]!='>' ) return 0;
i += 2;
}
return i;
}
/*
** The z[] input contains text mixed with TH1 scripts.
** The TH1 scripts are contained within <th1>...</th1>.
** TH1 variables are $aaa or $<aaa>. The first form of
** variable is literal. The second is run through htmlize
** before being inserted.
**
** This routine processes the template and writes the results
** on either stdout or into CGI.
*/
int Th_Render(const char *z){
int i = 0;
int n;
int rc = TH_OK;
uchar *zResult;
Th_FossilInit();
while( z[i] ){
if( z[i]=='$' && (n = validVarName(&z[i+1]))>0 ){
const char *zVar;
int nVar;
sendText(z, i, 0);
if( z[i+1]=='<' ){
/* Variables of the form $<aaa> */
zVar = &z[i+2];
nVar = n-2;
}else{
/* Variables of the form $aaa */
zVar = &z[i+1];
nVar = n;
}
rc = Th_GetVar(g.interp, (uchar*)zVar, nVar);
z += i+1+n;
i = 0;
zResult = (uchar*)Th_GetResult(g.interp, &n);
sendText((char*)zResult, n, n>nVar);
}else if( z[i]=='<' && isBeginScriptTag(&z[i]) ){
sendText(z, i, 0);
z += i+5;
for(i=0; z[i] && (z[i]!='<' || !isEndScriptTag(&z[i])); i++){}
rc = Th_Eval(g.interp, 0, (const uchar*)z, i);
if( rc!=TH_OK ) break;
z += i;
if( z[0] ){ z += 6; }
i = 0;
}else{
i++;
}
}
if( rc==TH_ERROR ){
sendText("<hr><p><font color=\"red\"><b>ERROR: ", -1, 0);
zResult = (uchar*)Th_GetResult(g.interp, &n);
sendText((char*)zResult, n, 1);
sendText("</b></font></p>", -1, 0);
}else{
sendText(z, i, 0);
}
return rc;
}
/*
** COMMAND: test-th-render
*/
void test_th_render(void){
Blob in;
if( g.argc<3 ){
usage("FILE");
}
blob_zero(&in);
blob_read_from_file(&in, g.argv[2]);
Th_Render(blob_str(&in));
}
|
Changes to src/timeline.c.
| ︙ | ︙ | |||
275 276 277 278 279 280 281 |
style_header("Timeline");
if( !g.okHistory &&
db_exists("SELECT 1 FROM user"
" WHERE login='anonymous'"
" AND cap LIKE '%%h%%'") ){
@ <p><b>Note:</b> You will be able to access <u>much</u> more
| | | 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
style_header("Timeline");
if( !g.okHistory &&
db_exists("SELECT 1 FROM user"
" WHERE login='anonymous'"
" AND cap LIKE '%%h%%'") ){
@ <p><b>Note:</b> You will be able to access <u>much</u> more
@ historical information if you <a href="%s(g.zTop)/login">login</a>.</p>
}
blob_zero(&sql);
blob_append(&sql, timeline_query_for_www(), -1);
if( zType ){
blob_appendf(&sql, " AND event.type=%Q", zType);
}
if( zUser ){
|
| ︙ | ︙ |
Changes to src/tkt.c.
| ︙ | ︙ | |||
34 35 36 37 38 39 40 | ** used. The internal-use fields begin with "tkt_". */ static int nField = 0; static char **azField = 0; /* Names of database fields */ static char **azValue = 0; /* Original values */ static char **azAppend = 0; /* Value to be appended */ | < < < < < | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
** used. The internal-use fields begin with "tkt_".
*/
static int nField = 0;
static char **azField = 0; /* Names of database fields */
static char **azValue = 0; /* Original values */
static char **azAppend = 0; /* Value to be appended */
/*
** Compare two entries in azField for sorting purposes
*/
static int nameCmpr(const void *a, const void *b){
return strcmp(*(char**)a, *(char**)b);
}
|
| ︙ | ︙ | |||
119 120 121 122 123 124 125 |
if( zVal==0 ) zVal = "";
for(j=0; j<nField; j++){
if( strcmp(azField[j],zName)==0 ){
azValue[j] = mprintf("%s", zVal);
break;
}
}
| | | | | | | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
if( zVal==0 ) zVal = "";
for(j=0; j<nField; j++){
if( strcmp(azField[j],zName)==0 ){
azValue[j] = mprintf("%s", zVal);
break;
}
}
if( Th_Fetch(zName, &size)==0 ){
Th_Store(db_column_name(&q,i), zVal);
}
}
}else{
db_finalize(&q);
db_prepare(&q, "PRAGMA table_info(ticket)");
while( db_step(&q)==SQLITE_ROW ){
const char *zField = db_column_text(&q, 1);
if( Th_Fetch(zField, &size)==0 ){
Th_Store(zField, "");
}
}
}
db_finalize(&q);
}
/*
** Transfer all CGI parameters to variables in the interpreter.
*/
static void initializeVariablesFromCGI(void){
int i;
const char *z;
for(i=0; (z = cgi_parameter_name(i))!=0; i++){
Th_Store(z, P(z));
}
}
/*
** Rebuild all tickets named in the _pending_ticket table.
**
** This routine is called just prior to commit after new
|
| ︙ | ︙ | |||
252 253 254 255 256 257 258 |
}
/*
** Create the subscript interpreter and load the ticket configuration.
*/
void ticket_init(void){
char *zConfig;
| | < | | | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
}
/*
** Create the subscript interpreter and load the ticket configuration.
*/
void ticket_init(void){
char *zConfig;
Th_FossilInit();
zConfig = db_text((char*)zDefaultTicketConfig,
"SELECT value FROM config WHERE name='ticket-configuration'");
Th_Eval(g.interp, 0, (const uchar*)zConfig, -1);
}
/*
** Recreate the ticket table.
*/
void ticket_create_table(int separateConnection){
char *zSql;
int nSql;
db_multi_exec("DROP TABLE IF EXISTS ticket;");
ticket_init();
zSql = (char*)Th_Fetch("ticket_sql", &nSql);
if( zSql==0 ){
fossil_panic("no ticket_sql defined by ticket configuration");
}
if( separateConnection ){
zSql = mprintf("%.*s", nSql, zSql);
db_init_database(g.zRepositoryName, zSql, 0);
free(zSql);
|
| ︙ | ︙ | |||
317 318 319 320 321 322 323 |
if( g.okWrTkt ){
style_submenu_element("Edit", "Edit The Ticket", "%s/tktedit?name=%T",
g.zTop, PD("name",""));
}
style_header("View Ticket");
ticket_init();
initializeVariablesFromDb();
| | | < < | | | > > > > > > | < > > | < < | > | | < | < | | > > > > > > | | 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 |
if( g.okWrTkt ){
style_submenu_element("Edit", "Edit The Ticket", "%s/tktedit?name=%T",
g.zTop, PD("name",""));
}
style_header("View Ticket");
ticket_init();
initializeVariablesFromDb();
zScript = (char*)Th_Fetch("tktview_template", &nScript);
zScript = mprintf("%.*s", nScript, zScript);
Th_Render(zScript);
style_footer();
}
/*
** TH command: append_field FIELD STRING
**
** FIELD is the name of a database column to which we might want
** to append text. STRING is the text to be appended to that
** column. The append does not actually occur until the
** submit_ticket command is run.
*/
static int appendRemarkCmd(
Th_Interp *interp,
void *p,
int argc,
const unsigned char **argv,
int *argl
){
int idx;
if( argc!=3 ){
return Th_WrongNumArgs(interp, "append_field FIELD STRING");
}
for(idx=0; idx<nField; idx++){
if( strncmp(azField[idx], (const char*)argv[1], argl[1])==0
&& azField[idx][argl[1]]==0 ){
break;
}
}
if( idx>=nField ){
Th_ErrorMessage(g.interp, "no such TICKET column: ", argv[1], argl[1]);
return TH_ERROR;
}
azAppend[idx] = mprintf("%.*s", argl[2], argv[2]);
return TH_OK;
}
/*
** Subscript command: submit_ticket
**
** Construct and submit a new ticket artifact.
*/
static int submitTicketCmd(
Th_Interp *interp,
void *pUuid,
int argc,
const unsigned char **argv,
int *argl
){
char *zDate;
const char *zUuid;
int i;
int rid;
Blob tktchng, cksum;
zUuid = (const char *)pUuid;
blob_zero(&tktchng);
zDate = db_text(0, "SELECT datetime('now')");
zDate[10] = 'T';
blob_appendf(&tktchng, "D %s\n", zDate);
free(zDate);
for(i=0; i<nField; i++){
const char *zValue;
int nValue;
if( azAppend[i] ){
blob_appendf(&tktchng, "J +%s %z\n", azField[i],
fossilize(azAppend[i], -1));
}else{
zValue = Th_Fetch(azField[i], &nValue);
if( zValue ){
while( nValue>0 && isspace(zValue[nValue-1]) ){ nValue--; }
if( strncmp(zValue, azValue[i], nValue)
|| strlen(azValue[i])!=nValue ){
blob_appendf(&tktchng, "J %s %z\n",
azField[i], fossilize(zValue,nValue));
}
|
| ︙ | ︙ | |||
409 410 411 412 413 414 415 |
blob_appendf(&tktchng, "Z %b\n", &cksum);
if( strncmp(g.zPath,"debug_",6)==0 ){
@ <hr><pre>
@ %h(blob_str(&tktchng))
@ </pre><hr>
blob_zero(&tktchng);
| < | | | 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 |
blob_appendf(&tktchng, "Z %b\n", &cksum);
if( strncmp(g.zPath,"debug_",6)==0 ){
@ <hr><pre>
@ %h(blob_str(&tktchng))
@ </pre><hr>
blob_zero(&tktchng);
return TH_OK;
}
rid = content_put(&tktchng, 0, 0);
if( rid==0 ){
fossil_panic("trouble committing ticket: %s", g.zErrMsg);
}
manifest_crosslink(rid, &tktchng);
return TH_RETURN;
}
/*
** WEBPAGE: tktnew
** WEBPAGE: debug_tktnew
**
|
| ︙ | ︙ | |||
444 445 446 447 448 449 450 451 452 |
char *zNewUuid = 0;
login_check_credentials();
if( !g.okNewTkt ){ login_needed(); return; }
style_header("New Ticket");
ticket_init();
getAllTicketFields();
initializeVariablesFromCGI();
@ <form method="POST" action="%s(g.zBaseURL)/%s(g.zPath)">
| > | | | | > | | 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 |
char *zNewUuid = 0;
login_check_credentials();
if( !g.okNewTkt ){ login_needed(); return; }
style_header("New Ticket");
ticket_init();
getAllTicketFields();
initializeVariablesFromDb();
initializeVariablesFromCGI();
@ <form method="POST" action="%s(g.zBaseURL)/%s(g.zPath)">
zScript = (char*)Th_Fetch("tktnew_template", &nScript);
zScript = mprintf("%.*s", nScript, zScript);
Th_Store("login", g.zLogin);
Th_Store("date", db_text(0, "SELECT datetime('now')"));
Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd,
(void*)&zNewUuid, 0);
if( Th_Render(zScript)==TH_RETURN && zNewUuid ){
cgi_redirect(mprintf("%s/tktview/%s", g.zBaseURL, zNewUuid));
return;
}
@ </form>
style_footer();
}
|
| ︙ | ︙ | |||
505 506 507 508 509 510 511 | } ticket_init(); getAllTicketFields(); initializeVariablesFromCGI(); initializeVariablesFromDb(); @ <form method="POST" action="%s(g.zBaseURL)/%s(g.zPath)"> @ <input type="hidden" name="name" value="%s(zName)"> | | | | | | | < | | | | < | < | < < < | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 |
}
ticket_init();
getAllTicketFields();
initializeVariablesFromCGI();
initializeVariablesFromDb();
@ <form method="POST" action="%s(g.zBaseURL)/%s(g.zPath)">
@ <input type="hidden" name="name" value="%s(zName)">
zScript = (char*)Th_Fetch("tktedit_template", &nScript);
zScript = mprintf("%.*s", nScript, zScript);
Th_Store("login", g.zLogin);
Th_Store("date", db_text(0, "SELECT datetime('now')"));
Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0);
Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0);
if( Th_Render(zScript)==TH_RETURN && zName ){
cgi_redirect(mprintf("%s/tktview/%s", g.zBaseURL, zName));
return;
}
@ </form>
style_footer();
}
/*
** Check the ticket configuration in zConfig to see if it appears to
** be well-formed. If everything is OK, return NULL. If something is
** amiss, then return a pointer to a string (obtained from malloc) that
** describes the problem.
*/
char *ticket_config_check(const char *zConfig){
char *zErr = 0;
const char *z;
int n;
int i;
int rc;
sqlite3 *db;
static const char *azRequired[] = {
"tktnew_template",
"tktview_template",
"tktedit_template",
};
Th_FossilInit();
rc = Th_Eval(g.interp, 0, (const uchar*)zConfig, strlen(zConfig));
if( rc!=TH_OK ){
zErr = (char*)Th_TakeResult(g.interp, 0);
return zErr;
}
for(i=0; i<sizeof(azRequired)/sizeof(azRequired[0]); i++){
z = Th_Fetch(azRequired[i], &n);
if( z==0 ){
zErr = mprintf("missing definition: %s", azRequired[i]);
return zErr;
}
}
z = Th_Fetch("ticket_sql", &n);
if( z==0 ){
zErr = mprintf("missing definition: ticket_sql");
return zErr;
}
rc = sqlite3_open(":memory:", &db);
if( rc==SQLITE_OK ){
char *zSql = mprintf("%.*s", n, z);
rc = sqlite3_exec(db, zSql, 0, 0, &zErr);
if( rc!=SQLITE_OK ){
sqlite3_close(db);
return zErr;
}
/* TODO: verify that the TICKET table exists and has required fields */
sqlite3_close(db);
}
return 0;
}
|
Changes to src/tktconfig.c.
| ︙ | ︙ | |||
31 32 33 34 35 36 37 | ** This is a sample "ticket configuration" file for fossil. ** ** There is considerable flexibility in how tickets are defined ** in fossil. Each repository can define its own ticket setup ** differently. Each repository has an instance of a file, like ** this one that defines how that repository deals with tickets. ** | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | | | | | | < | > | | | | > > | | | | | | | | > | < | | | | | | | | | > | | | | | | | | < | < | | | | | | | | | | | | | < | | | | | > | < | > | < | < | | | | < | | | | | | | | | | | | | | | | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
** This is a sample "ticket configuration" file for fossil.
**
** There is considerable flexibility in how tickets are defined
** in fossil. Each repository can define its own ticket setup
** differently. Each repository has an instance of a file, like
** this one that defines how that repository deals with tickets.
**
** This file is in the form of a script in TH1 - a minimalist
** TCL clone.
*/
/* @-comment: ** */
const char zDefaultTicketConfig[] =
@ ############################################################################
@ # Every ticket configuration *must* define an SQL statement that creates
@ # the TICKET table. This table must have three columns named
@ # tkt_id, tkt_uuid, and tkt_mtime. tkt_id must be the integer primary
@ # key and tkt_uuid and tkt_mtime must be unique. A configuration should
@ # define addition columns as necessary. All columns should be in all
@ # lower-case letters and should not begin with "tkt".
@ #
@ set ticket_sql {
@ CREATE TABLE ticket(
@ -- Do not change any column that begins with tkt_
@ tkt_id INTEGER PRIMARY KEY,
@ tkt_uuid TEXT,
@ tkt_mtime DATE,
@ -- Add as many field as required below this line
@ type TEXT,
@ status TEXT,
@ subsystem TEXT,
@ priority TEXT,
@ severity TEXT,
@ foundin TEXT,
@ contact TEXT,
@ resolution TEXT,
@ title TEXT,
@ comment TEXT,
@ -- Do not alter this UNIQUE clause:
@ UNIQUE(tkt_uuid, tkt_mtime)
@ );
@ -- Add indices as desired
@ }
@
@ ############################################################################
@ # You can define additional variables here. These variables will be
@ # accessible to the page templates when they run.
@ #
@ set type_choices {
@ Code_Defect
@ Build_Problem
@ Documentation
@ Feature_Request
@ Incident
@ }
@ set priority_choices {Immediate High Medium Low Zero}
@ set severity_choices {Critical Severe Important Minor Cosmetic}
@ set resolution_choices {
@ Open
@ Fixed
@ Rejected
@ Unable_To_Reproduce
@ Works_As_Designed
@ External_Bug
@ Not_A_Bug
@ Duplicate
@ Overcome_By_Events
@ Drive_By_Patch
@ }
@ set status_choices {
@ Open
@ Verified
@ In_Process
@ Deferred
@ Fixed
@ Tested
@ Closed
@ }
@ set subsystem_choices {one two three}
@
@ ##########################################################################
@ # The "tktnew_template" variable is set to text which is a template for
@ # the HTML of the "New Ticket" page. Within this template, text contained
@ # within [...] is subscript. That subscript runs when the page is
@ # rendered.
@ #
@ set tktnew_template {
@ <!-- load database field names not found in CGI with an empty string -->
@ <!-- start a form -->
@ <th1>
@ if {[info exists submit]} {
@ set status Open
@ submit_ticket
@ }
@ </th1>
@ <table cellpadding="5">
@ <tr>
@ <td colspan="2">
@ Enter a one-line summary of the problem:<br>
@ <input type="text" name="title" size="60" value="$<title>">
@ </td>
@ </tr>
@
@ <tr>
@ <td align="right">Type:
@ <th1>combobox type $type_choices 1</th1>
@ </td>
@ <td>What type of ticket is this?</td>
@ </tr>
@
@ <tr>
@ <td align="right">Version:
@ <input type="text" name="foundin" size="20" value="$<foundin>">
@ </td>
@ <td>In what version or build number do you observer the problem?</td>
@ </tr>
@
@ <tr>
@ <td align="right">Severity:
@ <th1>combobox severity $severity_choices 1</th1>
@ </td>
@ <td>How debilitating is the problem? How badly does the problem
@ effect the operation of the product?</td>
@ </tr>
@
@ <tr>
@ <td align="right">EMail:
@ <input type="text" name="contact" value="$<contact>" size="30">
@ </td>
@ <td>Not publically visible. Used by developers to contact you with
@ questions.</td>
@ </tr>
@
@ <tr>
@ <td colspan="2">
@ Enter a detailed description of the problem.
@ For code defects, be sure to provide details on exactly how
@ the problem can be reproduced. Provide as much detail as
@ possible.
@ <br>
@ <th1>set nline [linecount $comment 50 10]</th1>
@ <textarea name="comment" cols="80" rows="$nline"
@ wrap="virtual" class="wikiedit">$<comment></textarea><br>
@ <input type="submit" name="preview" value="Preview">
@ </tr>
@
@ <th1>enable_output [info exists preview]</th1>
@ <tr><td colspan="2">
@ Description Preview:<br><hr>
@ <th1>wiki $comment</th1>
@ <hr>
@ </td></tr>
@ <th1>enable_output 1</th1>
@
@ <tr>
@ <td align="right">
@ <input type="submit" name="submit" value="Submit">
@ </td>
@ <td>After filling in the information above, press this button to create
@ the new ticket</td>
@ </tr>
@ </table>
@ <!-- end of form -->
@ }
@
@ ##########################################################################
@ # The template for the "edit ticket" page
@ #
@ # Then generated text is inserted inside a form which feeds back to itself.
@ # All CGI parameters are loaded into variables. All database files are
@ # loaded into variables if they have not previously been loaded by
@ # CGI parameters.
@ set tktedit_template {
@ <th1>
@ if {![info exists username]} {set username $login}
@ if {[info exists submit]} {
@ if {[info exists $cmappnd] && [string length $cmappnd]>0} {
@ set ctxt "\n\n<hr><i>"
@ if {$username==$login} {
@ set usr "$ctxt[htmlize $login]"
@ } else {
@ set usr "[htmlize $login claimingn to be [htmlize $username]"
@ }
@ append_field comment \
@ "\n\n<hr><i>$usr added on [date]:</i><br>\n$comment"
@ }
@ submit_ticket
@ }
@ </th1>
@ <table cellpadding="5">
@ <tr><td align="right">Title:</td><td>
@ <input type="text" name="title" value="$<title>" size="60">
@ </td></tr>
@ <tr><td align="right">Status:</td><td>
@ <th1>combobox status $status_choices 1</th1>
@ </td></tr>
@ <tr><td align="right">Type:</td><td>
@ <th1>combobox type $type_choices 1</th1>
@ </td></tr>
@ <tr><td align="right">Severity:</td><td>
@ <th1>combobox severity $severity_choices 1</th1>
@ </td></tr>
@ <tr><td align="right">Priority:</td><td>
@ <th1>combobox priority $priority_choices 1</th1>
@ </td></tr>
@ <tr><td align="right">Resolution:</td><td>
@ <th1>combobox resolution $resolution_choices 1</th1>
@ </td></tr>
@ <tr><td align="right">Subsystem:</td><td>
@ <th1>combobox subsystem $subsystem_choices 1</th1>
@ </td></tr>
@ <th1>enable_output [hascap e]</th1>
@ <tr><td align="right">Contact:</td><td>
@ <input type="text" name="contact" size="40" value="$<contact>">
@ </td></tr>
@ <th1>enable_output 1</th1>
@ <tr><td align="right">Version Found In:</td><td>
@ <input type="text" name="foundin" size="50" value="$<foundin>">
@ </td></tr>
@ <tr><td colspan="2">
@ <th1>
@ if {![info exists eall]} {set eall 0}
@ if {[info exists aonlybtn]} {set eall 0}
@ if {[info exists eallbtn]} {set eall 1}
@ if {![hascap w]} {set eall 0}
@ if {![info exists cmappnd]} {set cmappnd {}}
@ set nline [linecount $comment 15 10]
@ enable_output $eall
@ </th1>
@ Description And Comments:<br>
@ <textarea name="comment" cols="80" rows="$nline"
@ wrap="virtual" class="wikiedit">$<comment></textarea><br>
@ <input type="hidden" name="eall" value="1">
@ <input type="submit" name="aonlybtn" value="Append Remark">
@ <th1>enable_output [expr {!$eall}]</th1>
@ Append Remark from
@ <input type="text" name="username" value="$<username>" size="30">:<br>
@ <textarea name="cmappnd" cols="80" rows="15"
@ wrap="virtual" class="wikiedit">$<cmappnd></textarea><br>
@ <th1>enable_output [expr {[hascap w] && !$eall}]</th1>
@ <input type="submit" name="eallbtn" value="Edit All">
@ <th1>enable_output 1</th1>
@ </td></tr>
@ <tr><td align="right"></td><td>
@ <input type="submit" name="submit" value="Submit Changes">
@ </td></tr>
@ </table>
@ }
@
@ ##########################################################################
@ # The template for the "view ticket" page
@ set tktview_template {
@ <!-- load database fields automatically loaded into variables -->
@ <table cellpadding="5">
@ <tr><td align="right">Title:</td><td>
@ $<title>
@ </td></tr>
@ <tr><td align="right">Status:</td><td>
@ $<status>
@ </td></tr>
@ <tr><td align="right">Type:</td><td>
@ $<type>
@ </td></tr>
@ <tr><td align="right">Severity:</td><td>
@ $<severity>
@ </td></tr>
@ <tr><td align="right">Priority:</td><td>
@ $<priority>
@ </td></tr>
@ <tr><td align="right">Resolution:</td><td>
@ $<resolution>
@ </td></tr>
@ <tr><td align="right">Subsystem:</td><td>
@ $<subsystem>
@ </td></tr>
@ <th1>enable_output [hascap e]</th1>
@ <tr><td align="right">Contact:</td><td>
@ $<contact>
@ </td></tr>
@ <th1>enable_output 1</th1>
@ <tr><td align="right">Version Found In:</td><td>
@ $<foundin>
@ </td></tr>
@ <tr><td colspan="2">
@ Description And Comments:<br>
@ <th1>wiki $comment</th1>
@ </td></tr>
@ </table>
@ }
;
|
Changes to src/update.c.
| ︙ | ︙ | |||
65 66 67 68 69 70 71 |
vid = db_lget_int("checkout", 0);
if( vid==0 ){
fossil_fatal("cannot find current version");
}
if( db_exists("SELECT 1 FROM vmerge") ){
fossil_fatal("cannot update an uncommitted merge");
}
| < < < < < < < | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
vid = db_lget_int("checkout", 0);
if( vid==0 ){
fossil_fatal("cannot find current version");
}
if( db_exists("SELECT 1 FROM vmerge") ){
fossil_fatal("cannot update an uncommitted merge");
}
if( g.argc==3 ){
tid = name_to_rid(g.argv[2]);
if( tid==0 ){
fossil_fatal("not a version: %s", g.argv[2]);
}
if( !is_a_version(tid) ){
|
| ︙ | ︙ |
Changes to src/zip.c.
| ︙ | ︙ | |||
370 371 372 373 374 375 376 377 378 379 380 |
rid = name_to_rid(zName);
if( rid==0 ){
@ Not found
return;
}
if( nName>10 ) zName[10] = 0;
zip_of_baseline(rid, &zip, zName);
cgi_set_content(&zip);
cgi_set_content_type("application/zip");
cgi_reply();
}
| > | 370 371 372 373 374 375 376 377 378 379 380 381 |
rid = name_to_rid(zName);
if( rid==0 ){
@ Not found
return;
}
if( nName>10 ) zName[10] = 0;
zip_of_baseline(rid, &zip, zName);
free( zName );
cgi_set_content(&zip);
cgi_set_content_type("application/zip");
cgi_reply();
}
|
Changes to www/fileformat.html.
1 2 3 4 5 6 7 8 9 10 11 12 13 | <html> <head> <title>Fossil File Format</title> </head> <body bgcolor="white"> <p>[ <a href="index.html">Index</a> ]</p> <hr> <h1 align="center"> Fossil File Formats </h1> <p> The global state of a fossil repository is determined by an unordered | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <html> <head> <title>Fossil File Format</title> </head> <body bgcolor="white"> <p>[ <a href="index.html">Index</a> ]</p> <hr> <h1 align="center"> Fossil File Formats </h1> <p> The global state of a fossil repository is determined by an unordered set of artifacts. An artifact might be a source code file, the text of a wiki page, part of a trouble ticket, or one of several special control artifacts used to show the relationships between other artifacts within the project. Artifacts can be text or binary. </p> <p> |
| ︙ | ︙ |
Changes to www/index.html.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 | </p> <p>Design Goals For Fossil:</p> <ul> <li>Supports disconnected, distributed development (like <a href="http://kerneltrap.org/node/4982">git</a>, | | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | </p> <p>Design Goals For Fossil:</p> <ul> <li>Supports disconnected, distributed development (like <a href="http://kerneltrap.org/node/4982">git</a>, <a href="http://www.monotone.ca/">monotone</a>, <a href="http://www.selenic.com/mercurial/wiki/index.cgi">mercurial</a>, or <a href="http://www.bitkeeper.com/">bitkeeper</a>) or client/server operation (like <a href="http://www.nongnu.org/cvs/">CVS</a> or <a href="http://subversion.tigris.org/">subversion</a>) or both at the same time</li> <li>Integrated bug tracking and wiki, along the lines of |
| ︙ | ︙ | |||
94 95 96 97 98 99 100 101 102 103 |
efficiently generate deltas.</li>
<li>The <a href="sync.html">synchronization protocol</a>.
<li>There is a <a href="http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users">
mailing list</a> available for discussing fossil issues.</li>
<li>The <a href="http://www.fossil-scm.org/fossil/wiki">self-hosting
fossil wiki</a>.
</ul>
</body>
</html>
| > > > > > > > > > > > > > | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
efficiently generate deltas.</li>
<li>The <a href="sync.html">synchronization protocol</a>.
<li>There is a <a href="http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users">
mailing list</a> available for discussing fossil issues.</li>
<li>The <a href="http://www.fossil-scm.org/fossil/wiki">self-hosting
fossil wiki</a>.
</ul>
<p>Competing Projects:</p>
<ul>
<li><a href="http://www.ditrack.org/">DITrace</a>
- A Distributed Issue Tracker</li>
<li><a href="http://www.distract.wellquite.org/">DisTract</a>
- Another distributed issue tracker based on
<a href="http://www.monotone.ca/">monotone</a>.
<li><a href="http://www.monotone.ca/">Monotone</a> - distributed
SCM in a single-file executable with a single-file SQLite
database repository.</li>
</ul>
</body>
</html>
|
Changes to www/pop.html.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 | <p> This page attempts to define the foundational principals upon which Fossil is built. </p> <ul> <li><p>A project consists of source files, wiki pages, and | > | | | | | | | | | | | | | | | | | | | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | <p> This page attempts to define the foundational principals upon which Fossil is built. </p> <ul> <li><p>A project consists of source files, wiki pages, and trouble tickets, and control files (collectively "artifacts"). All historical copies of all artifacts are saved. The project maintains an audit trail.</p></li> <li><p>A project resides in one or more repositories. Each repository is administered and operates independently of the others.</p></li> <li><p>Each repository has both global and local state. The global state is common to all repositories (or at least has the potential to be shared in common when the repositories are fully synchronized). The local state for each repository is private to that repository. The global state represents the content of the project. The local state identifies the authorized users and access policies for a particular repository.</p></li> <li><p>The global state of a repository is an unordered collection of artifacts. Each artifact is named by its SHA1 hash encoded in lowercase hexadecimal. In many contexts, the name can be abbreviated to a unique prefix. A five- or six-character prefix usually suffices to uniquely identify a file.</p></li> <li><p>Because artifacts are named by their SHA1 hash, all artifacts are immutable. Any change to the content of a artifact also changes the hash that forms the artifacts name, thus creating a new artifact. Both the old original version of the artifact and the new change are preserved under different names.</p></li> <li><p>It is theoretically possible for two artifacts with different content to share the same hash. But finding two such artifacts is so incredibly difficult and unlikely that we consider it to be an impossibility.</p></li> <li><p>The signature of an artifact is the SHA1 hash of the artifact itself, exactly as it would appear in a disk file. No prefix or meta-information about the artifact is added before computing the hash. So you can always find the SHA1 signature of a file by using the "sha1sum" command-line utility.</p></li> <li><p>The artifacts that comprise the global state of a repository are the complete global state of that repository. The SQLite database that holds the repository contains additional information about linkages between artifacts, but all of that added information can be discarded and reconstructed by rescanning the content artifacts.</p></li> <li><p>Two repositories for the same project can synchronize their global states simply by sharing artifacts. The local state of repositories is not normally synchronized or shared.</p></li> <li><p>Every baseline has a special file at the top-level named "manifest" which is an index of all other files in that baseline. The manifest is automatically created and maintained by the system.</p></li> <li><p>The <a href="fileformat.html">file formats</a> used by Fossil are all very simple so that with access to the original content files, one can easily reconstruct the content of a baseline without the need for any special tools or software.</p></li> </body> </html> |