Changeset 8003 for trunk/tools/common/kFile.cpp
- Timestamp:
- Feb 24, 2002, 3:47:28 AM (24 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/tools/common/kFile.cpp
r7093 r8003 1 /* $Id: kFile.cpp,v 1. 9 2001-10-17 14:21:10bird Exp $1 /* $Id: kFile.cpp,v 1.10 2002-02-24 02:47:24 bird Exp $ 2 2 * 3 3 * kFile - Simple (for the time being) file class. … … 27 27 #include <stdlib.h> 28 28 29 #include "kTypes.h" 30 #include "kError.h" 29 31 #include "kFile.h" 30 32 … … 43 45 * @remark 44 46 */ 45 BOOLkFile::refreshFileStatus()47 KBOOL kFile::refreshFileStatus() 46 48 { 47 49 if (fStdDev) … … 50 52 if (!fStatusClean) 51 53 { 52 rc = DosQueryFileInfo( hFile, FIL_QUERYEASIZE, &filestatus, sizeof(filestatus));54 rc = DosQueryFileInfo(OSData.os2.hFile, FIL_QUERYEASIZE, &OSData.os2.filestatus, sizeof(OSData.os2.filestatus)); 53 55 fStatusClean = (rc == NO_ERROR); 54 56 if (!fStatusClean && fThrowErrors) 55 throw ( (int)rc);57 throw (kError(rc)); 56 58 } 57 59 else … … 66 68 * @returns Success indicator. 67 69 */ 68 BOOLkFile::position()70 KBOOL kFile::position() 69 71 { 70 72 /* … … 75 77 { 76 78 ULONG off; 77 rc = DosSetFilePtr( hFile, offVirtual, FILE_BEGIN, &off);79 rc = DosSetFilePtr(OSData.os2.hFile, offVirtual, FILE_BEGIN, &off); 78 80 if (rc != NO_ERROR || off != offVirtual) 79 81 { 80 82 if (fThrowErrors) 81 throw ( (int)rc);83 throw (kError(rc)); 82 84 return FALSE; 83 85 } … … 99 101 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no) 100 102 */ 101 BOOL kFile::bufferRead(ULONG offFile) throw (int)103 KBOOL kFile::bufferRead(unsigned long offFile) throw(kError) 102 104 { 103 105 ULONG cbRead; … … 108 110 109 111 /* check that the request is valid */ 110 if (offFile > filestatus.cbFile)112 if (offFile > OSData.os2.filestatus.cbFile) 111 113 return FALSE; 112 114 … … 123 125 124 126 /* If readonly file optimize end of file */ 125 if (fReadOnly && cbBuffer + offFile > filestatus.cbFile)126 offFile = filestatus.cbFile > cbBuffer ?filestatus.cbFile - cbBuffer : 0UL;127 if (fReadOnly && cbBuffer + offFile > OSData.os2.filestatus.cbFile) 128 offFile = OSData.os2.filestatus.cbFile > cbBuffer ? OSData.os2.filestatus.cbFile - cbBuffer : 0UL; 127 129 128 130 /* need to change file ptr? */ … … 130 132 { 131 133 ULONG ul; 132 rc = DosSetFilePtr( hFile, offFile, FILE_BEGIN, &ul);134 rc = DosSetFilePtr(OSData.os2.hFile, offFile, FILE_BEGIN, &ul); 133 135 if (rc != NO_ERROR) 134 136 { 135 137 if (fThrowErrors) 136 throw ( (int)rc);138 throw (kError(rc)); 137 139 return FALSE; 138 140 } … … 141 143 142 144 /* read from the file */ 143 cbRead = min(filestatus.cbFile - offFile, cbBuffer);144 rc = DosRead( hFile, pachBuffer, cbRead, &cbRead);145 cbRead = KMIN(OSData.os2.filestatus.cbFile - offFile, cbBuffer); 146 rc = DosRead(OSData.os2.hFile, pachBuffer, cbRead, &cbRead); 145 147 if (rc == NO_ERROR) 146 148 { … … 156 158 fBufferDirty = FALSE; 157 159 if (fThrowErrors) 158 throw ( (int)rc);160 throw (kError(rc)); 159 161 return FALSE; 160 162 } … … 169 171 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no) 170 172 */ 171 BOOL kFile::bufferCommit(void) throw (int)173 KBOOL kFile::bufferCommit(void) throw(kError) 172 174 { 173 175 ULONG cbWrote; … … 181 183 if (offBuffer != offReal) 182 184 { 183 rc = DosSetFilePtr( hFile, offBuffer, FILE_BEGIN, &ul);185 rc = DosSetFilePtr(OSData.os2.hFile, offBuffer, FILE_BEGIN, &ul); 184 186 if (rc != NO_ERROR) 185 187 { 186 188 if (fThrowErrors) 187 throw ( (int)rc);189 throw (kError(rc)); 188 190 return FALSE; 189 191 } … … 192 194 193 195 /* write to the file */ 194 rc = DosWrite( hFile, pachBuffer, cbBufferValid, &cbWrote);196 rc = DosWrite(OSData.os2.hFile, pachBuffer, cbBufferValid, &cbWrote); 195 197 fStatusClean = FALSE; 196 198 if (rc == NO_ERROR) … … 201 203 else 202 204 { 203 DosSetFilePtr( hFile, offReal, FILE_BEGIN, &ul);205 DosSetFilePtr(OSData.os2.hFile, offReal, FILE_BEGIN, &ul); 204 206 if (fThrowErrors) 205 throw ( (int)rc);207 throw (kError(rc)); 206 208 return FALSE; 207 209 } … … 222 224 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no) 223 225 */ 224 kFile::kFile(HFILE hFile, BOOL fReadOnly)226 kFile::kFile(HFILE hFile, KBOOL fReadOnly) 225 227 : fReadOnly(fReadOnly), 226 228 fStatusClean(FALSE), … … 229 231 offReal(0), 230 232 pszFilename(NULL), 231 hFile(hFile),232 233 fStdDev(TRUE), 233 234 pachBuffer(NULL), … … 236 237 fBufferDirty(FALSE) 237 238 { 239 OSData.os2.hFile = hFile; 238 240 if (!refreshFileStatus()) 239 throw ( (int)rc);241 throw (kError(rc)); 240 242 this->pszFilename = strdup(""); 241 243 } … … 252 254 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no) 253 255 */ 254 kFile::kFile(const char *pszFilename, BOOL fReadOnly/*=TRUE*/)256 kFile::kFile(const char *pszFilename, KBOOL fReadOnly/*=TRUE*/) 255 257 : fReadOnly(fReadOnly), 256 258 fStatusClean(FALSE), … … 283 285 } 284 286 285 rc = DosOpen((PCSZ)pszFilename, & hFile, &ulAction, 0, FILE_NORMAL,287 rc = DosOpen((PCSZ)pszFilename, &OSData.os2.hFile, &ulAction, 0, FILE_NORMAL, 286 288 fulOpenFlags, fulOpenMode, NULL); 287 289 if (rc != NO_ERROR) 288 throw ( (int)rc);290 throw (kError(rc)); 289 291 290 292 if (!refreshFileStatus()) 291 throw ( (int)rc);293 throw (kError(rc)); 292 294 293 295 char szFullName[CCHMAXPATH]; … … 299 301 300 302 /* Buffering */ 301 cbBuffer = (fReadOnly && filestatus.cbFile < 32768) ?filestatus.cbFile : 8192;303 cbBuffer = (fReadOnly && OSData.os2.filestatus.cbFile < 32768) ? OSData.os2.filestatus.cbFile : 8192; 302 304 pachBuffer = new char[cbBuffer]; 303 305 if (pachBuffer == NULL) 304 306 throw (ERROR_NOT_ENOUGH_MEMORY); 305 if (fReadOnly && filestatus.cbFile < 32768)307 if (fReadOnly && OSData.os2.filestatus.cbFile < 32768) 306 308 { 307 309 if (!bufferRead(0)) 308 throw ( (int)rc);310 throw (kError(rc)); 309 311 } 310 312 } … … 320 322 if (pachBuffer) 321 323 delete pachBuffer; 322 DosClose( hFile);324 DosClose(OSData.os2.hFile); 323 325 } 324 326 … … 326 328 /** 327 329 * Reads <cbBuffer> bytes from the current file posistion into the buffer. 328 * @returns success indicator. (TRUE/FALSE)330 * @returns 0 on success. kError error number. 329 331 * @param pvBuffer Output buffer. 330 332 * @param cbBuffer Amount of bytes to read. 331 333 */ 332 BOOLkFile::read(void *pvBuffer, long cbBuffer)334 int kFile::read(void *pvBuffer, long cbBuffer) 333 335 { 334 336 ULONG cbRead; … … 336 338 /* Validate parameters */ 337 339 if (cbBuffer == 0) 338 return TRUE;340 return NO_ERROR; 339 341 if (cbBuffer < 0) 340 342 { 341 343 rc = ERROR_INVALID_PARAMETER; 342 344 if (fThrowErrors) 343 throw ( (int)rc);344 return FALSE;345 throw (kError(rc)); 346 return rc; 345 347 } 346 348 347 349 /* refresh file status (cbFile) */ 348 350 if (!refreshFileStatus()) 349 return FALSE;351 return rc; 350 352 351 353 /* check if valid request */ 352 if ( offVirtual > filestatus.cbFile353 || offVirtual + cbBuffer > filestatus.cbFile354 if ( offVirtual > OSData.os2.filestatus.cbFile 355 || offVirtual + cbBuffer > OSData.os2.filestatus.cbFile 354 356 ) 355 357 { /* invalid request */ 356 358 rc = ERROR_NO_DATA; 357 359 } 358 else if (this->cbBufferValid == filestatus.cbFile && offBuffer == 0)360 else if (this->cbBufferValid == OSData.os2.filestatus.cbFile && offBuffer == 0) 359 361 { 360 362 /* … … 386 388 { /* copy data from buffer */ 387 389 cbRead = cbBufferValid - offVirtual + offBuffer; 388 cbRead = min(cbRead, cbBuffer);390 cbRead = KMIN(cbRead, cbBuffer); 389 391 memcpy(pvBuffer, &pachBuffer[offVirtual - offBuffer], (size_t)cbRead); 390 392 offVirtual += cbRead; … … 396 398 /* read into buffer */ 397 399 if (!bufferRead(offVirtual)) 398 return FALSE;400 return rc; 399 401 } 400 402 } … … 406 408 * unbuffered read. 407 409 */ 408 rc = DosRead( hFile, pvBuffer, cbBuffer, &cbRead);410 rc = DosRead(OSData.os2.hFile, pvBuffer, cbBuffer, &cbRead); 409 411 if (rc == NO_ERROR) 410 412 offVirtual = offReal += cbRead; … … 412 414 413 415 /* check for error and return accordingly */ 414 if (rc) 415 { 416 if (fThrowErrors) 417 throw ((int)rc); 418 return FALSE; 419 } 420 return TRUE; 416 if (rc && fThrowErrors) 417 throw (kError(rc)); 418 return rc; 421 419 } 422 420 … … 424 422 /** 425 423 * Reads <cbBuffer> bytes at file offset <off>. 426 * @returns success indicator. (TRUE/FALSE)424 * @returns 0 on success. kError error number. 427 425 * @param pvBuffer Output buffer. 428 426 * @param cbBuffer Amount of bytes to read. 429 427 * @param off Absolute file offset. 430 428 */ 431 BOOL kFile::readAt(void *pvBuffer, long cbBuffer, long off) 432 { 433 return set(off) && read(pvBuffer, cbBuffer); 429 int kFile::readAt(void *pvBuffer, long cbBuffer, long off) 430 { 431 if (set(off)) 432 return rc; 433 read(pvBuffer, cbBuffer); 434 return rc; 434 435 } 435 436 … … 439 440 * (The memory block has a '\0' at the end just in case you 440 441 * are using it as a long string.) 442 * Must call the static kFile::mapFree function to free the memory block. 441 443 * @returns Pointer to file in memory. 442 444 */ 443 void * kFile:: readFile() throw(int)445 void * kFile::mapFile() throw(kError) 444 446 { 445 447 void *pv; … … 450 452 { 451 453 if (fThrowErrors) 452 throw (ERROR_NOT_ENOUGH_MEMORY);454 throw (kError(kError::NOT_ENOUGH_MEMORY)); 453 455 return NULL; 454 456 } 455 457 456 458 /* go the start of the file and read it. */ 457 if ( start() &&read(pv, this->getSize()))459 if (!start() && !read(pv, this->getSize())) 458 460 return pv; // successfull exit! 459 461 … … 467 469 * Reads a single line from the file into the given buffer. 468 470 * Newline is stripped! 469 * @returns Success indicator.471 * @returns 0 on success. kError error number. 470 472 * @param pszBuffer Pointer to string buffer. 471 473 * Will hold a zero-string upon successful return. … … 475 477 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no) 476 478 */ 477 BOOL kFile::readln(char *pszBuffer, long cchBuffer) throw (int)479 int kFile::readln(char *pszBuffer, long cchBuffer) throw(kError) 478 480 { 479 481 long cbRead; … … 481 483 /* refresh file status (cbFile) */ 482 484 if (!refreshFileStatus()) 483 return FALSE;485 return rc; 484 486 485 487 /* … … 488 490 * Loop buffer by buffer looking for a newline. 489 491 */ 490 cbRead = min(max((long)filestatus.cbFile - (long)offVirtual, 0), cchBuffer-1);492 cbRead = KMIN(KMAX((long)OSData.os2.filestatus.cbFile - (long)offVirtual, 0), cchBuffer-1); 491 493 if (cbRead == 0) 492 return FALSE;494 return rc = ERROR_HANDLE_EOF; 493 495 494 496 while (cbRead > 0) … … 502 504 if (offVirtual >= offBuffer + cbBufferValid || offVirtual < offBuffer) 503 505 if (!bufferRead(offVirtual)) 504 return FALSE;506 return rc; 505 507 506 508 /* Scan buffer for new line */ … … 542 544 else 543 545 offVirtual++; 544 return TRUE;545 } 546 } 547 548 return TRUE;546 return NO_ERROR; 547 } 548 } 549 550 return NO_ERROR; 549 551 } 550 552 … … 552 554 /** 553 555 * Writes <cbBuffer> bytes to the file at the current file position. 554 * @returns success indicator. (TRUE/FALSE)556 * @returns 0 on success. kError error number. 555 557 * @param pvBuffer Output buffer. 556 558 * @param cbBuffer Amount of bytes to write. 557 559 */ 558 BOOLkFile::write(const void *pv, long cb)560 int kFile::write(const void *pv, long cb) 559 561 { 560 562 if (fReadOnly) … … 604 606 offVirtual += cb + cbAddPost; 605 607 fBufferDirty = TRUE; 606 return TRUE;608 return NO_ERROR; 607 609 } 608 610 … … 634 636 { /* don't fit anywhere... */ 635 637 if (!bufferCommit()) 636 return FALSE;638 return rc; 637 639 offBuffer = offVirtual; 638 640 cbWrite = cbBufferValid = cb > cbBuffer ? cbBuffer : cb; … … 648 650 offVirtual += cbAddPost; 649 651 650 return TRUE;652 return NO_ERROR; 651 653 } 652 654 else if (position()) … … 654 656 ULONG cbWrote; 655 657 656 rc = DosWrite( hFile, (PVOID)pv, cb, &cbWrote);658 rc = DosWrite(OSData.os2.hFile, (PVOID)pv, cb, &cbWrote); 657 659 if (rc == NO_ERROR) 658 660 { 659 661 offVirtual = offReal += cbWrote; 660 return TRUE;662 return NO_ERROR; 661 663 } 662 664 } … … 664 666 665 667 if (fThrowErrors) 666 throw ( (int)rc);667 return FALSE;668 throw (kError(rc)); 669 return rc; 668 670 } 669 671 … … 671 673 /** 672 674 * Write <cbBuffer> bytes at file offset <off> from <pvBuffer>. 673 * @returns success indicator. (TRUE/FALSE)675 * @returns 0 on success. kError error number. 674 676 * @param pvBuffer Output buffer. 675 677 * @param cbBuffer Amount of bytes to write. 676 678 * @param off Absolute file offset. 677 679 */ 678 BOOL kFile::writeAt(void *pvBuffer, long cbBuffer, long off) 679 { 680 return set(off) && write(pvBuffer, cbBuffer); 680 int kFile::writeAt(const void *pvBuffer, long cbBuffer, long off) 681 { 682 if (set(off)) 683 return rc; 684 return write(pvBuffer, cbBuffer); 681 685 } 682 686 … … 693 697 * @remark Currently limited to 64KB of result data. 694 698 */ 695 int kFile::printf(const char *pszFormat, ...) throw (int)699 int kFile::printf(const char *pszFormat, ...) throw(kError) 696 700 { 697 701 long offStart = getPos(); … … 725 729 /** 726 730 * Sets the filesize. 727 * @returns Success indicator.731 * @returns 0 on success. kError error number. 728 732 * @param cbFile New filesize. 729 733 * Defaults to 0xffffffff, which results in 730 734 * cutting the file at the current position. 731 735 */ 732 BOOLkFile::setSize(unsigned long cbFile/*= ~0UL*/)736 int kFile::setSize(unsigned long cbFile/*= ~0UL*/) 733 737 { 734 738 if (cbFile == ~0UL) 735 739 cbFile = offVirtual; 736 rc = DosSetFileSize( hFile, cbFile);740 rc = DosSetFileSize(OSData.os2.hFile, cbFile); 737 741 if (rc != NO_ERROR && fThrowErrors) 738 throw ( (int)rc);739 740 return rc == NO_ERROR;742 throw (kError(rc)); 743 744 return rc; 741 745 } 742 746 … … 752 756 char * pachBuffer = new char[1024*256]; 753 757 long pos = AppendFile.getPos(); 754 BOOLfAppend = AppendFile.fThrowErrors;755 BOOLfThis = fThrowErrors;758 KBOOL fAppend = AppendFile.fThrowErrors; 759 KBOOL fThis = fThrowErrors; 756 760 757 761 setThrowOnErrors(); … … 762 766 AppendFile.refreshFileStatus(); 763 767 764 cb = min(1024*256, AppendFile.filestatus.cbFile);768 cb = KMIN(1024*256, AppendFile.OSData.os2.filestatus.cbFile); 765 769 while (cb > 0) 766 770 { 767 771 AppendFile.read(pachBuffer, cb); 768 772 write(pachBuffer, cb); 769 cb = min(1024*256, (long)AppendFile.filestatus.cbFile - (long)AppendFile.offVirtual);773 cb = KMIN(1024*256, (long)AppendFile.OSData.os2.filestatus.cbFile - (long)AppendFile.offVirtual); 770 774 } 771 775 … … 781 785 /** 782 786 * Seek relative to the current position. 783 * @returns Success indicator.787 * @returns 0 on success. kError error number. 784 788 * @param off Relative reposition. 785 789 */ 786 BOOLkFile::move(long off)790 int kFile::move(long off) 787 791 { 788 792 if ((off + offVirtual) & 0x80000000UL) /* above 2GB or negative */ … … 790 794 else 791 795 { 792 if (off + offVirtual > filestatus.cbFile && fReadOnly) /* can't expand readonly file. */796 if (off + offVirtual > OSData.os2.filestatus.cbFile && fReadOnly) /* can't expand readonly file. */ 793 797 rc = ERROR_HANDLE_EOF; 794 798 else 795 799 { 796 800 offVirtual += off; 797 return TRUE;801 return rc = NO_ERROR; 798 802 } 799 803 } 800 804 801 805 if (fThrowErrors) 802 throw ( (int)rc);803 return FALSE;806 throw (kError(rc)); 807 return rc; 804 808 } 805 809 … … 807 811 /** 808 812 * Seek to an absolute position in the file (off). 809 * @returns Success indicator.813 * @returns 0 on success. kError error number. 810 814 * @param off New file position. 811 815 */ 812 BOOLkFile::set(long off)816 int kFile::set(long off) 813 817 { 814 818 if (off < 0) … … 816 820 else 817 821 { 818 if ((unsigned long)off > filestatus.cbFile && fReadOnly)822 if ((unsigned long)off > OSData.os2.filestatus.cbFile && fReadOnly) 819 823 rc = ERROR_HANDLE_EOF; 820 824 else 821 825 { 822 826 offVirtual = off; 823 rc = NO_ERROR; 824 return TRUE; 827 return rc = NO_ERROR; 825 828 } 826 829 } 827 830 if (fThrowErrors) 828 throw ( (int)rc);829 return FALSE;831 throw (kError(rc)); 832 return rc; 830 833 } 831 834 … … 833 836 /** 834 837 * Seek to the end of the file. 835 * @returns Success indicator. TRUE / FALSE.838 * @returns 0 on success. kError error number. 836 839 * @remark Will only throw error if refreshFileStatus failes. 837 840 */ 838 BOOLkFile::end()841 int kFile::end() 839 842 { 840 843 if (!refreshFileStatus()) 841 return FALSE;842 843 if (!fReadOnly && pachBuffer && offBuffer != ~0UL && offBuffer + cbBufferValid > filestatus.cbFile)844 return rc; 845 846 if (!fReadOnly && pachBuffer && offBuffer != ~0UL && offBuffer + cbBufferValid > OSData.os2.filestatus.cbFile) 844 847 /* a writable file with buffer might have uncommited data in the buffer. */ 845 848 offVirtual = offBuffer + cbBufferValid; 846 849 else 847 offVirtual = filestatus.cbFile; 848 849 rc = NO_ERROR; 850 return TRUE; 850 offVirtual = OSData.os2.filestatus.cbFile; 851 852 return rc = NO_ERROR; 851 853 } 852 854 … … 854 856 /** 855 857 * Seek to the start of the file. 856 * @returns TRUE.858 * @returns 0 on success. kError error number. 857 859 * @remark Will never throw errors. 858 860 */ 859 BOOLkFile::start()861 int kFile::start() 860 862 { 861 863 offVirtual = 0; 862 rc = NO_ERROR; 863 return TRUE; 864 return rc = NO_ERROR; 864 865 } 865 866 … … 876 877 return -1; 877 878 878 return filestatus.cbFile;879 return OSData.os2.filestatus.cbFile; 879 880 } 880 881 … … 897 898 * @remark Will only throw error if refreshFileStatus failes. 898 899 */ 899 BOOLkFile::isEOF()900 KBOOL kFile::isEOF() 900 901 { 901 902 #if 0 902 throw (ERROR_NOT_SUPPORTED); //this method don't currently work! Need to use flag!903 throw (kError(kError::NOT_SUPPORTED)); //this method don't currently work! Need to use flag! 903 904 #else 904 905 if (!fReadOnly && !refreshFileStatus()) 905 return ( BOOL)-1;906 907 return filestatus.cbFile <= offVirtual; //??? - !!!906 return (KBOOL)-1; 907 908 return OSData.os2.filestatus.cbFile <= offVirtual; //??? - !!! 908 909 #endif 909 910 } … … 913 914 * Set error behaviour to fail by throwing the OS/2 return code when an 914 915 * error occures. 915 * @returns TRUE;916 916 * @remark Will never throw errors. 917 917 */ 918 BOOLkFile::setThrowOnErrors()918 void kFile::setThrowOnErrors() 919 919 { 920 920 fThrowErrors = TRUE; 921 921 rc = NO_ERROR; 922 return TRUE;923 922 } 924 923 … … 926 925 /** 927 926 * Set error behaviour to fail by return FALSE when an error has occures. 928 * @returns TRUE;929 927 * @remark Will never throw errors. 930 928 */ 931 BOOLkFile::setFailOnErrors()929 void kFile::setFailOnErrors() 932 930 { 933 931 fThrowErrors = FALSE; 934 932 rc = NO_ERROR; 935 return TRUE;936 933 } 937 934 … … 957 954 * @remark May throw errors. 958 955 */ 959 void *kFile:: readFile(const char *pszFilename)956 void *kFile::mapFile(const char *pszFilename) 960 957 { 961 958 kFile file(pszFilename); 962 return file.readFile(); 963 } 964 959 file.setThrowOnErrors(); 960 return file.mapFile(); 961 } 962 963 964 965 /** 966 * Frees a file mapping done by one of the mapFile members of kFile. 967 * @param pvFileMapping The pointer mapFile returned. 968 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no) 969 */ 970 void kFile::mapFree(void *pvFileMapping) 971 { 972 if (pvFileMapping) 973 free(pvFileMapping); 974 } 975
Note:
See TracChangeset
for help on using the changeset viewer.