ddnet/docs/doctool/NaturalDocs

387 lines
11 KiB
Plaintext
Raw Normal View History

2007-05-22 15:06:55 +00:00
#!/usr/bin/perl
=begin nd
Script: NaturalDocs
___________________________________________________________________________
Version 1.35
Copyright (C) 2003-2005 Greg Valure
http://www.naturaldocs.org
About: License
Licensed under the GNU General Public License
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
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 program; if not, visit http://www.gnu.org/licenses/gpl.txt
or write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA.
Topic: Code Conventions
- Every package function is called with an arrow operator. It's needed for inheritance in some places, and consistency
when it's not.
- No constant will ever be zero or undef. Those are reserved so any piece of code can allow a "none of the above" option
and not worry about conflicts with an existing value.
- Existence hashes are hashes where the value doesn't matter. It acts more as a set, where the existence of the key is
the significant part.
Topic: File Format Conventions
- All integers appear in big-endian format. So a UInt16 should be handled with a 'n' in pack and unpack, not with a 'S'.
- AString16's are a big-endian UInt16 followed by that many ASCII characters. A null-terminator is not stored.
- If a higher-level type is described in a file format, that means the loading and saving format is handled by that package.
For example, if you see <SymbolString> in the format, that means <NaturalDocs::SymbolString->ToBinaryFile()> and
<NaturalDocs::SymbolString->FromBinaryFile()> are used to manipulate it, and the underlying format should be treated
as opaque.
=cut
use strict;
use integer;
use 5.005; # When File::Spec was included by default
use English '-no_match_vars';
use FindBin;
use lib "$FindBin::RealBin/Modules";
sub INIT
{
# This function is just here so that when I start the debugger, it doesn't open a new file. Normally it would jump to an INIT
# function in some other file since that's the first piece of code to execute.
};
use NaturalDocs::Constants;
use NaturalDocs::SymbolString;
use NaturalDocs::ReferenceString;
use NaturalDocs::Topics;
use NaturalDocs::Version;
use NaturalDocs::File;
use NaturalDocs::ConfigFile;
use NaturalDocs::NDMarkup;
use NaturalDocs::Languages;
use NaturalDocs::Settings;
use NaturalDocs::Project;
use NaturalDocs::Menu;
use NaturalDocs::SymbolTable;
use NaturalDocs::ClassHierarchy;
use NaturalDocs::Parser;
use NaturalDocs::Builder;
use NaturalDocs::Error;
use NaturalDocs::StatusMessage;
###############################################################################
#
# Group: Basic Types
#
# Types used throughout the program. As Perl is a weakly-typed language unless you box things into objects, these types are
# for documentation purposes and are not enforced.
#
#
# Type: FileName
#
# A string representing the absolute, platform-dependent path to a file. Relative file paths are no longer in use anywhere in the
# program. All path manipulation should be done through <NaturalDocs::File>.
#
#
# Type: VersionInt
#
# A comparable integer representing a version number. Converting them to and from text and binary should be handled by
# <NaturalDocs::Version>.
#
#
# Type: SymbolString
#
# A scalar which encodes a normalized array of identifier strings representing a full or partially-resolved symbol. All symbols
# must be retrieved from plain text via <NaturalDocs::SymbolString->FromText()> so that the separation and normalization is
# always consistent. SymbolStrings are comparable via string compare functions and are sortable.
#
#
# Type: ReferenceString
#
# All the information about a reference that makes it unique encoded into a string. This includes the <SymbolString> of the
# reference, the scope <SymbolString> it appears in, the scope <SymbolStrings> it has access to via "using", and the
# <ReferenceType>. This is done because if any of those parameters change, it needs to be treated as a completely separate
# reference.
#
###############################################################################
# Group: Support Functions
# General functions that are used throughout the program, and that don't really fit anywhere else.
#
# Function: StringCompare
#
# Compares two strings so that the result is good for proper sorting. A proper sort orders the characters as
# follows:
#
# - End of string.
# - Whitespace. Line break-tab-space.
# - Symbols, which is anything not included in the other entries.
# - Numbers, 0-9.
# - Letters, case insensitive except to break ties.
#
# If you use cmp instead of this function, the result would go by ASCII/Unicode values which would place certain symbols
# between letters and numbers instead of having them all grouped together. Also, you would have to choose between case
# sensitivity or complete case insensitivity, in which ties are broken arbitrarily.
#
# Returns:
#
# Like cmp, it returns zero if A and B are equal, a positive value if A is greater than B, and a negative value if A is less than B.
#
sub StringCompare #(a, b)
{
my ($a, $b) = @_;
if (!defined $a)
{
if (!defined $b)
{ return 0; }
else
{ return -1; };
}
elsif (!defined $b)
{
return 1;
};
my $translatedA = lc($a);
my $translatedB = lc($b);
$translatedA =~ tr/\n\r\t 0-9a-z/\x01\x02\x03\x04\xDB-\xFE/;
$translatedB =~ tr/\n\r\t 0-9a-z/\x01\x02\x03\x04\xDB-\xFE/;
my $result = $translatedA cmp $translatedB;
if ($result == 0)
{
# Break the tie by comparing their case. Lowercase before uppercase.
# If statement just to keep everything theoretically kosher, even though in practice we don't need this.
if (ord('A') > ord('a'))
{ return ($a cmp $b); }
else
{ return ($b cmp $a); };
}
else
{ return $result; };
};
#
# Function: ShortenToMatchStrings
#
# Compares two arrayrefs and shortens the first array to only contain shared entries. Assumes all entries are strings.
#
# Parameters:
#
# sharedArrayRef - The arrayref that will be shortened to only contain common elements.
# compareArrayRef - The arrayref to match.
#
sub ShortenToMatchStrings #(sharedArrayRef, compareArrayRef)
{
my ($sharedArrayRef, $compareArrayRef) = @_;
my $index = 0;
while ($index < scalar @$sharedArrayRef && $index < scalar @$compareArrayRef &&
$sharedArrayRef->[$index] eq $compareArrayRef->[$index])
{ $index++; };
if ($index < scalar @$sharedArrayRef)
{ splice(@$sharedArrayRef, $index); };
};
#
# Function: XChomp
#
# A cross-platform chomp function. Regular chomp fails when parsing Windows-format line breaks on a Unix platform. It
# leaves the /r on, which screws everything up. This does not.
#
# Parameters:
#
# lineRef - A *reference* to the line to chomp.
#
sub XChomp #(lineRef)
{
my $lineRef = shift;
$$lineRef =~ s/[\n\r]+$//;
};
#
# Function: FindFirstSymbol
#
# Searches a string for a number of symbols to see which appears first.
#
# Parameters:
#
# string - The string to search.
# symbols - An arrayref of symbols to look for.
# index - The index to start at, if any.
#
# Returns:
#
# The array ( index, symbol ).
#
# index - The index the first symbol appears at, or -1 if none appear.
# symbol - The symbol that appeared, or undef if none.
#
sub FindFirstSymbol #(string, symbols, index)
{
my ($string, $symbols, $index) = @_;
if (!defined $index)
{ $index = 0; };
my $lowestIndex = -1;
my $lowestSymbol;
foreach my $symbol (@$symbols)
{
my $testIndex = index($string, $symbol, $index);
if ($testIndex != -1 && ($lowestIndex == -1 || $testIndex < $lowestIndex))
{
$lowestIndex = $testIndex;
$lowestSymbol = $symbol;
};
};
return ($lowestIndex, $lowestSymbol);
};
###############################################################################
#
# Main Code
#
# The order in which functions are called here is critically important. Read the "Usage and Dependencies" sections of all the
# packages before even thinking about rearranging these.
#
eval {
# Check that our required packages are okay.
NaturalDocs::File->CheckCompatibility();
# Almost everything requires Settings to be initialized.
NaturalDocs::Settings->Load();
NaturalDocs::Project->LoadConfigFileInfo();
NaturalDocs::Topics->Load();
NaturalDocs::Languages->Load();
# Migrate from the old file names that were used prior to 1.14.
NaturalDocs::Project->MigrateOldFiles();
if (!NaturalDocs::Settings->IsQuiet())
{ print "Finding files and detecting changes...\n"; };
NaturalDocs::Project->LoadSourceFileInfo();
NaturalDocs::SymbolTable->Load();
NaturalDocs::ClassHierarchy->Load();
NaturalDocs::SymbolTable->Purge();
NaturalDocs::ClassHierarchy->Purge();
# Parse any supported files that have changed.
my $filesToParse = NaturalDocs::Project->FilesToParse();
my $amount = scalar keys %$filesToParse;
if ($amount > 0)
{
NaturalDocs::StatusMessage->Start('Parsing ' . $amount . ' file' . ($amount > 1 ? 's' : '') . '...', $amount);
foreach my $file (keys %$filesToParse)
{
NaturalDocs::Parser->ParseForInformation($file);
NaturalDocs::StatusMessage->CompletedItem();
};
};
# The symbol table is now fully resolved, so we can reduce its memory footprint.
NaturalDocs::SymbolTable->PurgeResolvingInfo();
# Load and update the menu file. We need to do this after parsing so when it is updated, it will detect files where the
# default menu title has changed and files that have added or deleted Natural Docs content.
NaturalDocs::Menu->LoadAndUpdate();
# Build any files that need it. This needs to be run regardless of whether there are any files to build. It will handle its own
# output messages.
NaturalDocs::Builder->Run();
# Write the changes back to disk.
NaturalDocs::Menu->Save();
NaturalDocs::Project->SaveSourceFileInfo();
NaturalDocs::SymbolTable->Save();
NaturalDocs::ClassHierarchy->Save();
NaturalDocs::Settings->Save();
NaturalDocs::Topics->Save();
NaturalDocs::Languages->Save();
# Must be done last.
NaturalDocs::Project->SaveConfigFileInfo();
if (!NaturalDocs::Settings->IsQuiet())
{ print "Done.\n"; };
};
if ($EVAL_ERROR) # Oops.
{
NaturalDocs::Error->HandleDeath();
};