~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Frontier Kernel
Frontier/Common/source/fileloop.c

Version: ~ [ 10.0 ] ~

** Warning: Cannot open xref database.

1 2 /* $Id: fileloop.c,v 1.5 2005/01/24 17:16:47 icreedon Exp $ */ 3 4 /****************************************************************************** 5 6 UserLand Frontier(tm) -- High performance Web content management, 7 object database, system-level and Internet scripting environment, 8 including source code editing and debugging. 9 10 Copyright (C) 1992-2004 UserLand Software, Inc. 11 12 This program is free software; you can redistribute it and/or modify 13 it under the terms of the GNU General Public License as published by 14 the Free Software Foundation; either version 2 of the License, or 15 (at your option) any later version. 16 17 This program is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 GNU General Public License for more details. 21 22 You should have received a copy of the GNU General Public License 23 along with this program; if not, write to the Free Software 24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 26 ******************************************************************************/ 27 28 #include "frontier.h" 29 #include "standard.h" 30 31 #include "memory.h" 32 #include "strings.h" 33 #include "error.h" 34 #include "file.h" 35 #include "oplist.h" 36 #include "fileloop.h" 37 38 39 40 41 #ifdef MACVERSION 42 typedef struct tyfilelooprecord { 43 44 short vnum; /*the volume we're looping through*/ 45 46 long dirid; /*the folder we're looking in*/ 47 48 short ixdirectory; /*index for the next file to look at*/ 49 50 hdllistrecord hfilelist; /*a list of filenames to be looped over*/ 51 } tyfilelooprecord, *ptrfilelooprecord, **hdlfilelooprecord; 52 53 54 55 56 static boolean fileloopreleaseitem (Handle h) { 57 58 /* 59 callback routine that disposes of one of our items. since there are no 60 handles linked into our handle, there's nothing to release. 61 62 I just wanted to have one of these around so the next guy that uses the 63 list facilty knows how to link a releaseitem callback routine. 64 */ 65 66 return (true); 67 } /*fileloopreleaseitem*/ 68 69 70 boolean diskinitloop (tyfileloopcallback diskfilter, Handle *hdiskloop) { 71 72 /* 73 same as fileinitloop, but for volumes on line 74 75 8/15/92 dmb: added, but commented out, diskfilter support 76 */ 77 78 tyfilelooprecord info; 79 ParamBlockRec pb; 80 register hdlfilelooprecord h; 81 short ix; 82 hdllistrecord hlist; 83 84 clearbytes (&pb, sizeof (pb)); /*init all fields to zero*/ 85 86 clearbytes (&info, sizeof (info)); 87 88 info.ixdirectory = 1; /*start with the first file*/ 89 90 if (!newfilledhandle (&info, sizeof (info), hdiskloop)) 91 return (false); 92 93 h = (hdlfilelooprecord) *hdiskloop; /*copy into register*/ 94 95 hlist = nil; 96 97 if (!opnewlist (&hlist, false)) 98 goto error; 99 100 (**h).hfilelist = hlist; 101 102 opsetreleaseitemcallback (hlist, &fileloopreleaseitem); 103 104 ix = 1; /*start with file index 1*/ 105 106 while (true) { 107 FSSpec fsvol; 108 OSErr errcode; 109 Handle hstring; 110 #if TARGET_API_MAC_CARBON == 1 111 HFSUniStr255 theName; 112 //Code change by Timothy Paustian Thursday, June 29, 2000 10:29:59 AM 113 //Updated to modern call for volume infomation 114 //Ii am checking this now against the original. 115 FSVolumeRefNum vRefNum;//this is just a SInt16 116 117 //Watch out that the fsvol.name parameter works as expected. 118 //this is still not working the way it should 119 errcode = FSGetVolumeInfo(0, ix, &vRefNum, kFSVolInfoNone, nil, &theName, nil); 120 if (errcode == nsvErr) /*not an error, just ran out of volumes*/ 121 return (true); 122 123 { 124 UnicodeToTextInfo theInfo; 125 UnicodeMapping theMapping; 126 theMapping.unicodeEncoding = kTextEncodingUnicodeDefault; 127 theMapping.otherEncoding = kTextEncodingMacRoman; 128 theMapping.mappingVersion = kUnicodeUseLatestMapping; 129 errcode = CreateUnicodeToTextInfo(&theMapping,&theInfo); 130 if (oserror (errcode)) // 1/29/97 dmb: call oserror 131 goto error; 132 //fsvol.name[0] = theName.length; 133 errcode = ConvertFromUnicodeToPString (theInfo, theName.length * 2, theName.unicode, fsvol.name); 134 if (oserror (errcode)) // 1/29/97 dmb: call oserror 135 goto error; 136 } 137 ix++; 138 fsvol.vRefNum = vRefNum; 139 140 #else //not carbon 141 pb.volumeParam.ioVolIndex = ix++; 142 143 pb.volumeParam.ioNamePtr = fsvol.name; 144 145 errcode = PBGetVInfoSync (&pb); 146 fsvol.vRefNum = pb.volumeParam.ioVRefNum; 147 148 if (errcode == nsvErr) /*not an error, just ran out of volumes*/ 149 return (true); 150 #endif//end carbon 151 152 if (errcode == nsvErr) /*not an error, just ran out of volumes*/ 153 return (true); 154 155 if (oserror (errcode)) // 1/29/97 dmb: call oserror 156 goto error; 157 158 fsvol.parID = fsRtParID; 159 160 if (!newfilledhandle (&fsvol, sizeof (fsvol), &hstring)) 161 goto error; 162 163 if (!oppushhandle (hlist, nil, (Handle) hstring)) 164 goto error; 165 166 } /*while*/ 167 168 error: 169 170 opdisposelist (hlist); 171 172 disposehandle (*hdiskloop); 173 174 *hdiskloop = nil; 175 176 return (false); 177 } /*diskinitloop*/ 178 179 180 boolean fileinitloop (const tyfilespec *fs, tyfileloopcallback filefilter, Handle *hfileloop) { 181 182 /* 183 a conglomeration of filemanager incantations which sets up a UserLand 184 fileloop construct. we create a new handle (allows fileloops to be 185 nested inside other file loops, not statically allocated) and fill it 186 with information that each iteration of a fileloop will need. took 187 a minimum of two days fiddling (3/16-17/90) to get this to work -- DW. 188 189 12/6/91 dmb: generate dirNFErr when fileparsevolname fails 190 191 8/15/92 dmb: added, but commented out, filefilter support 192 193 2.1b2 dmb: updated to use filespecs 194 195 3.0.2 dmb: make sure fs is a folder, not a file 196 */ 197 198 tyfilelooprecord info; 199 CInfoPBRec pb; 200 long dirid; 201 register hdlfilelooprecord h; 202 short ix; 203 hdllistrecord hlist; 204 205 clearbytes (&pb, sizeof (CInfoPBRec)); /*init all fields to zero*/ 206 207 setoserrorparam ((ptrstring) (*fs).name); 208 209 pb.hFileInfo.ioVRefNum = (*fs).vRefNum; 210 211 pb.hFileInfo.ioDirID = (*fs).parID; 212 213 pb.hFileInfo.ioNamePtr = (StringPtr) (*fs).name; 214 215 if (oserror (PBGetCatInfoSync (&pb))) 216 return (false); 217 218 if (!foldertest (&pb)) { /*3.0.2*/ 219 220 oserror (dirNFErr); 221 222 return (false); 223 } 224 225 dirid = pb.dirInfo.ioDrDirID; /*must remember this for loop body*/ 226 227 clearbytes (&info, sizeof (info)); 228 229 info.vnum = pb.hFileInfo.ioVRefNum; 230 231 info.dirid = pb.hFileInfo.ioDirID; 232 233 info.ixdirectory = 1; /*start with the first file*/ 234 235 if (!newfilledhandle (&info, sizeof (info), hfileloop)) 236 return (false); 237 238 h = (hdlfilelooprecord) *hfileloop; /*copy into register*/ 239 240 hlist = nil; 241 242 if (!opnewlist (&hlist, false)) 243 goto error; 244 245 (**h).hfilelist = hlist; 246 247 opsetreleaseitemcallback (hlist, &fileloopreleaseitem); 248 249 ix = 1; /*start with file index 1*/ 250 251 while (true) { 252 253 bigstring bsfile; 254 Handle hstring; 255 OSErr errcode; 256 257 pb.dirInfo.ioDrDirID = dirid; /*may be smashed by ioFlNum on previous loop*/ 258 259 pb.dirInfo.ioFDirIndex = ix++; 260 261 pb.dirInfo.ioNamePtr = bsfile; 262 263 errcode = PBGetCatInfoSync (&pb); 264 265 if (errcode == fnfErr) /*not an error, just ran out of files*/ 266 return (true); 267 268 #if TARGET_API_MAC_CARBON == 1 269 270 if (errcode == dirNFErr) /*On OS X, this is what's returned for a read permission error. Weird.*/ 271 return (true); 272 273 if (errcode == afpAccessDenied) /* 2005-01-05 creedon - don't bail when user does not have the correct permissions < http://sourceforge.net/tracker/index.php?func=detail&aid=1096641&group_id=120666&atid=687798 > */ 274 return (true); 275 276 #endif 277 278 if (oserror (errcode)) /*errcode != noErr*/ 279 goto error; 280 281 /*if it's a folder, insert a colon at the end of the file name*/ 282 283 if (foldertest (&pb)) 284 if (!pushchar (':', bsfile)) 285 goto error; 286 287 /* 288 if (filefilter != nil) { 289 290 if (!(*filefilter) (bspath, bsfile)) 291 continue; 292 } 293 */ 294 295 if (!newtexthandle (bsfile, &hstring)) 296 goto error; 297 298 if (!oppushhandle (hlist, nil, (Handle) hstring)) 299 goto error; 300 } /*while*/ 301 302 error: 303 304 opdisposelist (hlist); 305 306 disposehandle (*hfileloop); 307 308 *hfileloop = nil; 309 310 return (false); 311 } /*fileinitloop*/ 312 313 314 void fileendloop (Handle hfileloop) { 315 316 register hdlfilelooprecord h = (hdlfilelooprecord) hfileloop; 317 318 opdisposelist ((**h).hfilelist); 319 320 disposehandle ((Handle) h); 321 } /*fileendloop*/ 322 323 324 boolean filenextloop (Handle hfileloop, tyfilespec *fsfile, boolean *flfolder) { 325 326 /* 327 8/17/92 dmb: we're using text handles now instead of string handles. 328 329 2.1b2 dmb: now we're using filespecs! 330 331 2.1b11 dmb: for volumes, whole fsspec is now stashed in handle 332 333 3.0.2b1 dmb: must set flfolder to true for disks 334 335 3.0.4b1 dmb: return true of fnfErr; script will have to handle error anyway 336 337 5.0.2b21 dmb: don't call FSMakeFSSpec for each file; just the first. 338 */ 339 340 register hdlfilelooprecord h = (hdlfilelooprecord) hfileloop; 341 Handle hdata; 342 bigstring bs; 343 short vnum; 344 long dirid; 345 OSErr err; 346 347 if (!opgetlisthandle ((**h).hfilelist, (**h).ixdirectory++, nil, &hdata)) 348 return (false); 349 350 vnum = (**h).vnum; 351 352 if (vnum == 0) { /*item is a volume, hdata contains refnum*/ 353 354 /* 355 vnum = **(short **) hdata; 356 357 setemptystring (bs); 358 */ 359 360 *fsfile = **(FSSpec **) hdata; 361 362 *flfolder = true; /*3.0.2b1*/ 363 364 return (true); 365 } 366 else { 367 368 dirid = (**h).dirid; 369 370 texthandletostring (hdata, bs); 371 372 *flfolder = bs [*bs] == ':'; 373 374 if (*flfolder) 375 --*bs; 376 377 if ((**h).ixdirectory == 2) { //first time 378 379 err = FSMakeFSSpec (vnum, dirid, bs, fsfile); 380 381 (**h).vnum = (*fsfile).vRefNum; 382 383 (**h).dirid = (*fsfile).parID; 384 385 if ((err == noErr) || (err == fnfErr)) /* 3.0.4b1 dmb */ 386 return (true); 387 388 return (!oserror (err)); /* false */ 389 } 390 else { 391 392 (*fsfile).vRefNum = vnum; 393 394 (*fsfile).parID = dirid; 395 396 copystring (bs, (*fsfile).name); 397 398 return (true); 399 } 400 } 401 } /*filenextloop*/ 402 403 404 boolean diskloop (tyfileloopcallback diskcallback, long refcon) { 405 406 /* 407 dmb 9/21/93: filegetvolumeinfo takes a vRefNum, not a string. 408 */ 409 410 HVolumeParam pb; 411 short ix; 412 413 clearbytes (&pb, sizeof (pb)); /*init all fields to zero*/ 414 415 ix = 1; /*start with file index 1*/ 416 417 while (true) { 418 419 bigstring bsvolume; 420 tyfileinfo info; 421 OSErr errcode; 422 423 pb.ioVolIndex = ix++; 424 425 pb.ioNamePtr = bsvolume; 426 427 errcode = PBHGetVInfoSync ((HParmBlkPtr) &pb); 428 429 if (errcode == nsvErr) /*not an error, just ran out of volumes*/ 430 return (true); 431 432 if (oserror (errcode)) 433 return (false); 434 435 filegetvolumeinfo (pb.ioVRefNum, &info); 436 437 if (!(*diskcallback) (bsvolume, &info, refcon)) 438 return (false); 439 } /*while*/ 440 } /*diskloop*/ 441 442 443 boolean folderloop (const tyfilespec *pfs, boolean flreverse, tyfileloopcallback filecallback, long refcon) { 444 445 /* 446 loop through all of the files in the folder at fs, and call filecallback 447 for each one. 448 449 if flreverse is true, loop through files backwards to allow for deletions 450 451 DW 8/28/93: inexplicably, getmacfileinfo is determining that ctfiles is 1 452 greater than the actual number of files in our folder (it's the History 453 folder in clayhistorymenu.c). the way the loop was structured, we visit 454 no files in the folder in this case. changed it so that on fnfErr we 455 continue the loop. the next time thru it will find a file. hope this 456 doesn't break anything else (it shouldn't). 457 */ 458 459 FSSpec fs = *pfs; /*work with a copy*/ 460 CInfoPBRec pb; 461 long dirid; 462 bigstring bsfile; 463 short ix; 464 long ctfiles; 465 tyfileinfo info; 466 OSErr ec; 467 468 setoserrorparam ((ptrstring) fs.name); 469 470 if (!getmacfileinfo (&fs, &pb)) 471 return (false); 472 473 assert (BitTst (&pb.dirInfo.ioFlAttrib, 3)); /*be sure it's a folder*/ 474 475 dirid = pb.dirInfo.ioDrDirID; /*must remember this for loop body*/ 476 477 ctfiles = pb.dirInfo.ioDrNmFls; 478 479 if (flreverse) 480 ix = ctfiles; 481 else 482 ix = 1; /*start with file index 1*/ 483 484 while (--ctfiles >= 0) { 485 486 pb.dirInfo.ioDrDirID = dirid; /*may be smashed by ioFlNum on previous loop*/ 487 488 pb.dirInfo.ioFDirIndex = ix; 489 490 if (flreverse) 491 --ix; 492 else 493 ++ix; 494 495 pb.dirInfo.ioNamePtr = bsfile; 496 497 ec = PBGetCatInfoSync (&pb); 498 499 if (ec == fnfErr) /*DW 8/28/93: continue instead of returning true*/ 500 continue; 501 502 if (oserror (ec)) 503 return (false); 504 505 filegetinfofrompb (&pb, &info); 506 507 if (!(*filecallback) (bsfile, &info, refcon)) 508 return (false); 509 } /*while*/ 510 511 return (true); 512 } /*folderloop*/ 513 #endif 514 515 516 517 518 #ifdef WIN95VERSION 519 // start windows version...... 520 typedef struct tyfindloopinfo 521 { 522 tyfilespec fs; 523 HANDLE findhandle; 524 tyfileloopcallback ffilter; 525 boolean doingDrives; 526 short drivenum; 527 } findloopinfo; 528 529 static boolean initfileloopspec (tyfilespec *fs) 530 { 531 HANDLE findHandle; 532 WIN32_FIND_DATA fileinfo; 533 char fn[300]; 534 char * filename; 535 short isFolder; 536 537 copystring (fsname (fs), fn); 538 filename = fsname (fs); 539 540 if (fileisvolume (fs)) { 541 cleanendoffilename (fsname (fs)); 542 appendcstring (filename, "\\*"); 543 return (true); 544 } 545 546 cleanendoffilename (fn); 547 nullterminate (fn); 548 549 findHandle = FindFirstFile (stringbaseaddress(fn), &fileinfo); 550 551 if (findHandle == INVALID_HANDLE_VALUE) 552 { 553 oserror (GetLastError()); 554 return (false); //no match 555 } 556 557 isFolder = (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)?true:false; 558 559 if (FindNextFile (findHandle, &fileinfo)) 560 { 561 FindClose (findHandle); 562 return (true); //wild card must be present to find second 563 } 564 565 FindClose (findHandle); 566 if (isFolder) { 567 cleanendoffilename (filename); 568 569 appendcstring (filename, "\\*"); 570 571 nullterminate (filename); 572 } 573 574 return (true); 575 } 576 577 boolean fileinitloop (const tyfilespec *pfs, tyfileloopcallback filefilter, Handle *hfileloop) { 578 579 findloopinfo ** fi; 580 581 *hfileloop = NULL; 582 fi = (findloopinfo **) NewHandle (sizeof(findloopinfo)); 583 584 if (fi == NULL) 585 return (false); 586 587 (**fi).fs = *pfs; 588 (**fi).findhandle = NULL; 589 (**fi).ffilter = filefilter; 590 (**fi).doingDrives = false; 591 (**fi).drivenum = 0; /*start with A*/ 592 593 if (isemptystring ((**fi).fs.fullSpecifier)) { /* do disks */ 594 (**fi).doingDrives = true; 595 } 596 else { 597 initfileloopspec (&((**fi).fs)); 598 } 599 600 *hfileloop = (Handle)fi; 601 return (true); 602 } 603 604 void fileendloop (Handle hfileloop) { 605 606 findloopinfo ** fi; 607 fi = (findloopinfo **) hfileloop; 608 609 if (fi != NULL) 610 { 611 if ((**fi).findhandle != NULL) 612 FindClose ((**fi).findhandle); 613 614 disposehandle ((Handle) fi); 615 } 616 } /*fileendloop*/ 617 618 619 boolean filenextloop (Handle hfileloop, tyfilespec *fsfile, boolean *flfolder) { 620 findloopinfo ** fi; 621 HANDLE findHandle; 622 WIN32_FIND_DATA fileinfo; 623 char fn[300]; 624 char pathname[300]; 625 char * endofpath; 626 int errCode; 627 short drivenum; 628 DWORD drivemap, drivemask; 629 630 if (hfileloop == NULL) 631 return (false); 632 633 if (fsfile == NULL) 634 return (false); 635 636 fi = (findloopinfo **) hfileloop; 637 638 if ((**fi).doingDrives) { /*We are looping over each volume - not files*/ 639 while (true) { 640 drivenum = (**fi).drivenum; 641 642 ++((**fi).drivenum); 643 644 if (drivenum >= 26) 645 return (false); 646 647 drivemap = GetLogicalDrives(); 648 649 drivemask = 1 << drivenum; 650 651 if ((drivemap & drivemask) == drivemask) { /* we found one */ 652 /*convert drivenum to filespec */ 653 wsprintf (stringbaseaddress(fsname(fsfile)), "%c:\\", drivenum + 'A'); 654 setstringlength (fsname(fsfile), strlen(stringbaseaddress(fsname(fsfile)))); 655 *flfolder = true; 656 return (true); 657 } 658 } 659 } 660 661 if ((**fi).findhandle == NULL) /*we are looking for the first one...*/ 662 { 663 copystring (fsname (&(**fi).fs), fn); 664 665 cleanendoffilename (fn); 666 667 nullterminate (fn); 668 669 findHandle = FindFirstFile (stringbaseaddress(fn), &fileinfo); 670 671 if (findHandle == INVALID_HANDLE_VALUE) 672 { 673 oserror (GetLastError()); 674 return (false); 675 } 676 677 GetFullPathName (stringbaseaddress(fn), 300, stringbaseaddress(pathname), &endofpath); 678 679 *endofpath = 0; /*terminates path name*/ 680 681 setstringlength(pathname, strlen(stringbaseaddress(pathname))); 682 683 copystring (pathname, fsname (&(**fi).fs)); 684 buildfilename (fsname (&(**fi).fs), 0, fileinfo.cFileName, 1, fsname (fsfile)); 685 686 if (flfolder != NULL) 687 *flfolder = (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)?true:false; 688 689 (**fi).findhandle = findHandle; 690 691 if (strcmp (fileinfo.cFileName, ".") == 0) 692 goto SkippingDotandDotDot; 693 694 if (strcmp (fileinfo.cFileName, "..") == 0) 695 goto SkippingDotandDotDot; 696 697 if (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 698 cleanendoffilename (fsname(fsfile)); 699 appendcstring (fsname(fsfile), "\\"); 700 } 701 702 return (true); 703 } 704 else 705 { 706 SkippingDotandDotDot: 707 if (FindNextFile ((**fi).findhandle, &fileinfo)) 708 { 709 buildfilename (fsname (&(**fi).fs), 0, fileinfo.cFileName, 1, fsname (fsfile)); 710 711 if (flfolder != NULL) 712 *flfolder = (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)?true:false; 713 714 if (strcmp (fileinfo.cFileName, ".") == 0) 715 goto SkippingDotandDotDot; 716 717 if (strcmp (fileinfo.cFileName, "..") == 0) 718 goto SkippingDotandDotDot; 719 720 if (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 721 cleanendoffilename (fsname(fsfile)); 722 appendcstring (fsname(fsfile), "\\"); 723 } 724 725 return (true); 726 } 727 728 errCode = GetLastError(); 729 730 // FindClose((**fi).findhandle); 731 732 if (errCode != ERROR_NO_MORE_FILES) 733 oserror(errCode); 734 } 735 736 return (false); 737 } 738 739 740 boolean folderloop (const tyfilespec *pfs, boolean flreverse, tyfileloopcallback filecallback, long refcon) { 741 HANDLE findHandle; 742 WIN32_FIND_DATA fileinfo; 743 char fn[300]; 744 char pathname[300]; 745 char * endofpath; 746 bigstring bsfile; 747 tyfileinfo info; 748 int errCode; 749 750 751 copystring (fsname (pfs), fn); 752 753 cleanendoffilename (fn); 754 755 nullterminate (fn); 756 757 findHandle = FindFirstFile (stringbaseaddress(fn), &fileinfo); 758 759 if (findHandle == INVALID_HANDLE_VALUE) 760 { 761 oserror (GetLastError()); 762 return (false); 763 } 764 765 winsetfileinfo (&fileinfo, &info); 766 767 GetFullPathName (stringbaseaddress(fn), 300, stringbaseaddress(pathname), &endofpath); 768 769 *endofpath = 0; /*terminates path name*/ 770 771 setstringlength(pathname, strlen(stringbaseaddress(pathname))); 772 773 buildfilename (pathname, 0, fileinfo.cFileName, 1, bsfile); 774 775 if (!(*filecallback) (bsfile, &info, refcon)) 776 { 777 FindClose(findHandle); 778 return (false); 779 } 780 781 while (FindNextFile (findHandle, &fileinfo)) 782 { 783 winsetfileinfo (&fileinfo, &info); 784 785 buildfilename (pathname, 0, fileinfo.cFileName, 1, bsfile); 786 787 if (!(*filecallback) (bsfile, &info, refcon)) 788 { 789 FindClose(findHandle); 790 return (false); 791 } 792 } 793 794 errCode = GetLastError(); 795 796 FindClose(findHandle); 797 798 if (errCode == ERROR_NO_MORE_FILES) 799 return (true); 800 801 oserror(errCode); 802 return (false); 803 } 804 805 #endif 806 807

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.