diff options
Diffstat (limited to 'docs/doctool/Modules/NaturalDocs/Settings.pm')
| -rw-r--r-- | docs/doctool/Modules/NaturalDocs/Settings.pm | 1258 |
1 files changed, 1258 insertions, 0 deletions
diff --git a/docs/doctool/Modules/NaturalDocs/Settings.pm b/docs/doctool/Modules/NaturalDocs/Settings.pm new file mode 100644 index 00000000..084c77bc --- /dev/null +++ b/docs/doctool/Modules/NaturalDocs/Settings.pm @@ -0,0 +1,1258 @@ +############################################################################### +# +# Package: NaturalDocs::Settings +# +############################################################################### +# +# A package to handle the command line and various other program settings. +# +# Usage and Dependencies: +# +# - The <Constant Functions> can be called immediately. +# +# - Prior to initialization, <NaturalDocs::Builder> must have all its output packages registered. +# +# - To initialize, call <Load()>. All functions except <InputDirectoryNameOf()> will then be available. +# +# - <GenerateDirectoryNames()> must be called before <InputDirectoryNameOf()> will work. Currently it is called by +# <NaturalDocs::Menu->LoadAndUpdate()>. +# +############################################################################### + +# This file is part of Natural Docs, which is Copyright (C) 2003-2005 Greg Valure +# Natural Docs is licensed under the GPL + +use Cwd (); + +use NaturalDocs::Settings::BuildTarget; + +use strict; +use integer; + +package NaturalDocs::Settings; + + + +############################################################################### +# Group: Variables + + +# handle: SETTINGSFILEHANDLE +# The file handle used with <Settings.txt>. + +# handle: PREVIOUS_SETTINGS_FILEHANDLE +# The file handle used with <PreviousSettings.nd>. + +# array: inputDirectories +# An array of input directories. +my @inputDirectories; + +# array: inputDirectoryNames +# An array of the input directory names. Each name corresponds to the directory of the same index in <inputDirectories>. +my @inputDirectoryNames; + +# array: excludedInputDirectories +# An array of input directories to exclude. +my @excludedInputDirectories; + +# array: removedInputDirectories +# An array of input directories that were once in the command line but are no longer. +my @removedInputDirectories; + +# array: removedInputDirectoryNames +# An array of the removed input directories names. Each name corresponds to the directory of the same index in +# <removedInputDirectories>. +my @removedInputDirectoryNames; + +# var: projectDirectory +# The project directory. +my $projectDirectory; + +# array: buildTargets +# An array of <NaturalDocs::Settings::BuildTarget>s. +my @buildTargets; + +# var: documentedOnly +# Whether undocumented code aspects should be included in the output. +my $documentedOnly; + +# int: tabLength +# The number of spaces in tabs. +my $tabLength; + +# bool: noAutoGroup +# Whether auto-grouping is turned off. +my $noAutoGroup; + +# bool: isQuiet +# Whether the script should be run in quiet mode or not. +my $isQuiet; + +# array: styles +# An array of style names to use, most important first. +my @styles; + +# var: charset +# The character encoding of the source files, and thus the output. +my $charset; + + +############################################################################### +# Group: Files + +# +# File: Settings.txt +# +# The file that stores the Natural Docs build targets. +# +# Format: +# +# The file is plain text. Blank lines can appear anywhere and are ignored. Tags and their content must be completely +# contained on one line. +# +# > # [comment] +# +# The file supports single-line comments via #. They can appear alone on a line or after content. +# +# > Format: [version] +# > TabLength: [length] +# > Style: [style] +# +# The file format version, tab length, and default style are specified as above. Each can only be specified once, with +# subsequent ones being ignored. Notice that the tags correspond to the long forms of the command line options. +# +# > Source: [directory] +# > Input: [directory] +# +# The input directory is specified as above. As in the command line, either "Source" or "Input" can be used. +# +# > [Extension Option]: [opton] +# +# Options for extensions can be specified as well. The long form is used as the tag. +# +# > Option: [HeadersOnly], [Quiet], [Extension Option] +# +# Options that don't have parameters can be specified in an Option line. The commas are not required. +# +# > Output: [name] +# +# Specifies an output target with a user defined name. The name is what will be referenced from the command line, and the +# name "All" is reserved. +# +# *The options below can only be specified after an output tag.* Everything that follows an output tag is part of that target's +# options until the next output tag. +# +# > Format: [format] +# +# The output format of the target. +# +# > Directory: [directory] +# > Location: [directory] +# > Folder: [directory] +# +# The output directory of the target. All are synonyms. +# +# > Style: [style] +# +# The style of the output target. This overrides the default and is optional. +# + + +# +# File: PreviousSettings.nd +# +# Stores the previous command line settings. +# +# Format: +# +# > [BINARY_FORMAT] +# > [VersionInt: app version] +# +# The file starts with the standard <BINARY_FORMAT> <VersionInt> header. +# +# > [UInt8: tab length] +# > [UInt8: documented only (0 or 1)] +# > [UInt8: no auto-group (0 or 1)] +# > [AString16: charset] +# > +# > [UInt8: number of input directories] +# > [AString16: input directory] [AString16: input directory name] ... +# +# A count of input directories, then that number of directory/name pairs. +# +# > [UInt8: number of output targets] +# > [AString16: output directory] [AString16: output format command line option] ... +# +# A count of output targets, then that number of directory/format pairs. +# +# +# Revisions: +# +# 1.33: +# +# - Added charset. +# +# 1.3: +# +# - Removed headers-only, which was a 0/1 UInt8 after tab length. +# - Change auto-group level (1 = no, 2 = yes, 3 = full only) to no auto-group (0 or 1). +# +# 1.22: +# +# - Added auto-group level. +# +# 1.2: +# +# - File was added to the project. Prior to 1.2, it didn't exist. +# + + +############################################################################### +# Group: Action Functions + +# +# Function: Load +# +# Loads and parses all settings from the command line and configuration files. Will exit if the options are invalid or the syntax +# reference was requested. +# +sub Load + { + my ($self) = @_; + + $self->ParseCommandLine(); + $self->LoadAndComparePreviousSettings(); + }; + + +# +# Function: Save +# +# Saves all settings in configuration files to disk. +# +sub Save + { + my ($self) = @_; + + $self->SavePreviousSettings(); + }; + + +# +# Function: GenerateDirectoryNames +# +# Generates names for each of the input directories, which can later be retrieved with <InputDirectoryNameOf()>. +# +# Parameters: +# +# hints - A hashref of suggested names, where the keys are the directories and the values are the names. These take +# precedence over anything generated. You should include names for directories that are no longer in the command +# line. This parameter may be undef. +# +sub GenerateDirectoryNames #(hints) + { + my ($self, $hints) = @_; + + my %usedNames; + + + if (defined $hints) + { + # First, we have to convert all non-numeric names to numbers, since they may come from a pre-1.32 menu file. We do it + # here instead of in NaturalDocs::Menu to keep the naming scheme centralized. + + my @names = values %$hints; + my $hasNonNumeric; + + foreach my $name (@names) + { + if ($name !~ /^[0-9]+$/) + { + $hasNonNumeric = 1; + last; + }; + }; + + + if ($hasNonNumeric) + { + # Hash mapping old names to new names. + my %conversion; + + # The sequential number to use. Starts at two because we want 'default' to be one. + my $currentNumber = 2; + + # If there's only one name, we set it to one no matter what it was set to before. + if (scalar @names == 1) + { $conversion{$names[0]} = 1; } + else + { + # We sort the list first because we want the end result to be predictable. This conversion could be happening on many + # machines, and they may not all specify the input directories in the same order. They need to all come up with the + # same result. + @names = sort @names; + + foreach my $name (@names) + { + if ($name eq 'default') + { $conversion{$name} = 1; } + else + { + $conversion{$name} = $currentNumber; + $currentNumber++; + }; + }; + }; + + # Convert them to the new names. + foreach my $directory (keys %$hints) + { + $hints->{$directory} = $conversion{ $hints->{$directory} }; + }; + }; + + + # Now we apply all the names from the hints. + + for (my $i = 0; $i < scalar @inputDirectories; $i++) + { + if (exists $hints->{$inputDirectories[$i]}) + { + $inputDirectoryNames[$i] = $hints->{$inputDirectories[$i]}; + $usedNames{ $hints->{$inputDirectories[$i]} } = 1; + delete $hints->{$inputDirectories[$i]}; + }; + }; + + + # Any remaining hints are saved as removed directories. + + while (my ($directory, $name) = each %$hints) + { + push @removedInputDirectories, $directory; + push @removedInputDirectoryNames, $name; + }; + }; + + + # Now we generate names for anything remaining. + + my $nameCounter = 1; + + for (my $i = 0; $i < scalar @inputDirectories; $i++) + { + if (!defined $inputDirectoryNames[$i]) + { + while (exists $usedNames{$nameCounter}) + { $nameCounter++; }; + + $inputDirectoryNames[$i] = $nameCounter; + $usedNames{$nameCounter} = 1; + + $nameCounter++; + }; + }; + }; + + + +############################################################################### +# Group: Information Functions + + +# +# Function: InputDirectories +# +# Returns an arrayref of input directories. Do not change. +# +# This will not return any removed input directories. +# +sub InputDirectories + { return \@inputDirectories; }; + +# +# Function: InputDirectoryNameOf +# +# Returns the generated name of the passed input directory. <GenerateDirectoryNames()> must be called once before this +# function is available. +# +# If a name for a removed input directory is available, it will be returned as well. +# +sub InputDirectoryNameOf #(directory) + { + my ($self, $directory) = @_; + + my $name; + + for (my $i = 0; $i < scalar @inputDirectories && !defined $name; $i++) + { + if ($directory eq $inputDirectories[$i]) + { $name = $inputDirectoryNames[$i]; }; + }; + + for (my $i = 0; $i < scalar @removedInputDirectories && !defined $name; $i++) + { + if ($directory eq $removedInputDirectories[$i]) + { $name = $removedInputDirectoryNames[$i]; }; + }; + + return $name; + }; + + +# +# Function: SplitFromInputDirectory +# +# Takes an input file name and returns the array ( inputDirectory, relativePath ). +# +# If the file cannot be split from an input directory, it will try to do it with the removed input directories. +# +sub SplitFromInputDirectory #(file) + { + my ($self, $file) = @_; + + foreach my $directory (@inputDirectories, @removedInputDirectories) + { + if (NaturalDocs::File->IsSubPathOf($directory, $file)) + { return ( $directory, NaturalDocs::File->MakeRelativePath($directory, $file) ); }; + }; + + return ( ); + }; + +# Function: ExcludedInputDirectories +# Returns an arrayref of input directories to exclude. Do not change. +sub ExcludedInputDirectories + { return \@excludedInputDirectories; }; + +# Function: BuildTargets +# Returns an arrayref of <NaturalDocs::Settings::BuildTarget>s. Do not change. +sub BuildTargets + { return \@buildTargets; }; + +# +# Function: OutputDirectoryOf +# +# Returns the output directory of a builder object. +# +# Parameters: +# +# object - The builder object, whose class is derived from <NaturalDocs::Builder::Base>. +# +# Returns: +# +# The builder directory, or undef if the object wasn't found.. +# +sub OutputDirectoryOf #(object) + { + my ($self, $object) = @_; + + foreach my $buildTarget (@buildTargets) + { + if ($buildTarget->Builder() == $object) + { return $buildTarget->Directory(); }; + }; + + return undef; + }; + + +# Function: Styles +# Returns an arrayref of the styles associated with the output. +sub Styles + { return \@styles; }; + +# Function: ProjectDirectory +# Returns the project directory. +sub ProjectDirectory + { return $projectDirectory; }; + +# Function: ProjectDataDirectory +# Returns the project data directory. +sub ProjectDataDirectory + { return NaturalDocs::File->JoinPaths($projectDirectory, 'Data', 1); }; + +# Function: StyleDirectory +# Returns the main style directory. +sub StyleDirectory + { return NaturalDocs::File->JoinPaths($FindBin::RealBin, 'Styles', 1); }; + +# Function: JavaScriptDirectory +# Returns the main JavaScript directory. +sub JavaScriptDirectory + { return NaturalDocs::File->JoinPaths($FindBin::RealBin, 'JavaScript', 1); }; + +# Function: ConfigDirectory +# Returns the main configuration directory. +sub ConfigDirectory + { return NaturalDocs::File->JoinPaths($FindBin::RealBin, 'Config', 1); }; + +# Function: DocumentedOnly +# Returns whether undocumented code aspects should be included in the output. +sub DocumentedOnly + { return $documentedOnly; }; + +# Function: TabLength +# Returns the number of spaces tabs should be expanded to. +sub TabLength + { return $tabLength; }; + +# Function: NoAutoGroup +# Returns whether auto-grouping is turned off. +sub NoAutoGroup + { return $noAutoGroup; }; + +# Function: IsQuiet +# Returns whether the script should be run in quiet mode or not. +sub IsQuiet + { return $isQuiet; }; + +# Function: CharSet +# Returns the character set, or undef if none. +sub CharSet + { return $charset; }; + + +############################################################################### +# Group: Constant Functions + +# +# Function: AppVersion +# +# Returns Natural Docs' version number as an integer. Use <TextAppVersion()> to get a printable version. +# +sub AppVersion + { + my ($self) = @_; + return NaturalDocs::Version->FromString($self->TextAppVersion()); + }; + +# +# Function: TextAppVersion +# +# Returns Natural Docs' version number as plain text. +# +sub TextAppVersion + { return '1.35'; }; + +# +# Function: AppURL +# +# Returns a string of the project's current web address. +# +sub AppURL + { return 'http://www.naturaldocs.org'; }; + + + +############################################################################### +# Group: Support Functions + + +# +# Function: ParseCommandLine +# +# Parses and validates the command line. Will cause the script to exit if the options ask for the syntax reference or +# are invalid. +# +sub ParseCommandLine + { + my ($self) = @_; + + my %synonyms = ( 'input' => '-i', + 'source' => '-i', + 'excludeinput' => '-xi', + 'excludesource' => '-xi', + 'output' => '-o', + 'project' => '-p', + 'documentedonly' => '-do', + 'style' => '-s', + 'rebuild' => '-r', + 'rebuildoutput' => '-ro', + 'tablength' => '-t', + 'quiet' => '-q', + 'headersonly' => '-ho', + 'help' => '-h', + 'autogroup' => '-ag', + 'noautogroup' => '-nag', + 'charset' => '-cs', + 'characterset' => '-cs' ); + + + my @errorMessages; + + my $valueRef; + my $option; + + my @outputStrings; + + + # Sometimes $valueRef is set to $ignored instead of undef because we don't want certain errors to cause other, + # unnecessary errors. For example, if they set the input directory twice, we want to show that error and swallow the + # specified directory without complaint. Otherwise it would complain about the directory too as if it were random crap + # inserted into the command line. + my $ignored; + + my $index = 0; + + while ($index < scalar @ARGV) + { + my $arg = $ARGV[$index]; + + if (substr($arg, 0, 1) eq '-') + { + $option = lc($arg); + + # Support options like -t2 as well as -t 2. + if ($option =~ /^([^0-9]+)([0-9]+)$/) + { + $option = $1; + splice(@ARGV, $index + 1, 0, $2); + }; + + # Convert long forms to short. + if (substr($option, 1, 1) eq '-') + { + # Strip all dashes. + my $newOption = $option; + $newOption =~ tr/-//d; + + if (exists $synonyms{$newOption}) + { $option = $synonyms{$newOption}; } + } + + if ($option eq '-i') + { + push @inputDirectories, undef; + $valueRef = \$inputDirectories[-1]; + } + elsif ($option eq '-xi') + { + push @excludedInputDirectories, undef; + $valueRef = \$excludedInputDirectories[-1]; + } + elsif ($option eq '-p') + { + if (defined $projectDirectory) + { + push @errorMessages, 'You cannot have more than one project directory.'; + $valueRef = \$ignored; + } + else + { $valueRef = \$projectDirectory; }; + } + elsif ($option eq '-o') + { + push @outputStrings, undef; + $valueRef = \$outputStrings[-1]; + } + elsif ($option eq '-s') + { + $valueRef = \$styles[0]; + } + elsif ($option eq '-t') + { + $valueRef = \$tabLength; + } + elsif ($option eq '-cs') + { + $valueRef = \$charset; + } + elsif ($option eq '-ag') + { + push @errorMessages, 'The -ag setting is no longer supported. You can use -nag (--no-auto-group) to turn off ' + . "auto-grouping, but there aren't multiple levels anymore."; + $valueRef = \$ignored; + } + + # Options that aren't followed by content. + else + { + $valueRef = undef; + + if ($option eq '-r') + { + NaturalDocs::Project->ReparseEverything(); + NaturalDocs::Project->RebuildEverything(); + } + elsif ($option eq '-ro') + { + NaturalDocs::Project->RebuildEverything(); + } + elsif ($option eq '-do') + { $documentedOnly = 1; } + elsif ($option eq '-q') + { $isQuiet = 1; } + elsif ($option eq '-ho') + { + push @errorMessages, 'The -ho setting is no longer supported. You can have Natural Docs skip over the source file ' + . 'extensions by editing Languages.txt in your project directory.'; + } + elsif ($option eq '-nag') + { $noAutoGroup = 1; } + elsif ($option eq '-?' || $option eq '-h') + { + $self->PrintSyntax(); + exit; + } + else + { push @errorMessages, 'Unrecognized option ' . $option; }; + + }; + + } + + # Is a segment of text, not an option... + else + { + if (defined $valueRef) + { + # We want to preserve spaces in paths. + if (defined $$valueRef) + { $$valueRef .= ' '; }; + + $$valueRef .= $arg; + } + + else + { + push @errorMessages, 'Unrecognized element ' . $arg; + }; + }; + + $index++; + }; + + + # Validate the style, if specified. + + if ($styles[0]) + { + my @stylePieces = split(/ +/, $styles[0]); + @styles = ( ); + + while (scalar @stylePieces) + { + if (lc($stylePieces[0]) eq 'custom') + { + push @errorMessages, 'The "Custom" style setting is no longer supported. Copy your custom style sheet to your ' + . 'project directory and you can refer to it with -s.'; + shift @stylePieces; + } + else + { + # People may use styles with spaces in them. If a style doesn't exist, we need to join the pieces until we find one that + # does or we run out of pieces. + + my $extras = 0; + my $success; + + while ($extras < scalar @stylePieces) + { + my $style; + + if (!$extras) + { $style = $stylePieces[0]; } + else + { $style = join(' ', @stylePieces[0..$extras]); }; + + my $cssFile = NaturalDocs::File->JoinPaths( $self->StyleDirectory(), $style . '.css' ); + if (-e $cssFile) + { + push @styles, $style; + splice(@stylePieces, 0, 1 + $extras); + $success = 1; + last; + } + else + { + $cssFile = NaturalDocs::File->JoinPaths( $self->ProjectDirectory(), $style . '.css' ); + + if (-e $cssFile) + { + push @styles, $style; + splice(@stylePieces, 0, 1 + $extras); + $success = 1; + last; + } + else + { $extras++; }; + }; + }; + + if (!$success) + { + push @errorMessages, 'The style "' . $stylePieces[0] . '" does not exist.'; + shift @stylePieces; + }; + }; + }; + } + else + { @styles = ( 'Default' ); }; + + + # Decode and validate the output strings. + + my %outputDirectories; + + foreach my $outputString (@outputStrings) + { + my ($format, $directory) = split(/ /, $outputString, 2); + + if (!defined $directory) + { push @errorMessages, 'The -o option needs two parameters: -o [format] [directory]'; } + else + { + if (!NaturalDocs::File->PathIsAbsolute($directory)) + { $directory = NaturalDocs::File->JoinPaths(Cwd::cwd(), $directory, 1); }; + + $directory = NaturalDocs::File->CanonizePath($directory); + + if (! -e $directory || ! -d $directory) + { + # They may have forgotten the format portion and the directory name had a space in it. + if (-e ($format . ' ' . $directory) && -d ($format . ' ' . $directory)) + { + push @errorMessages, 'The -o option needs two parameters: -o [format] [directory]'; + $format = undef; + } + else + { push @errorMessages, 'The output directory ' . $directory . ' does not exist.'; } + } + elsif (exists $outputDirectories{$directory}) + { push @errorMessages, 'You cannot specify the output directory ' . $directory . ' more than once.'; } + else + { $outputDirectories{$directory} = 1; }; + + if (defined $format) + { + my $builderPackage = NaturalDocs::Builder->OutputPackageOf($format); + + if (defined $builderPackage) + { + push @buildTargets, + NaturalDocs::Settings::BuildTarget->New(undef, $builderPackage->New(), $directory); + } + else + { + push @errorMessages, 'The output format ' . $format . ' doesn\'t exist or is not installed.'; + $valueRef = \$ignored; + }; + }; + }; + }; + + if (!scalar @buildTargets) + { push @errorMessages, 'You did not specify an output directory.'; }; + + + # Make sure the input and project directories are specified, canonized, and exist. + + if (scalar @inputDirectories) + { + for (my $i = 0; $i < scalar @inputDirectories; $i++) + { + if (!NaturalDocs::File->PathIsAbsolute($inputDirectories[$i])) + { $inputDirectories[$i] = NaturalDocs::File->JoinPaths(Cwd::cwd(), $inputDirectories[$i], 1); }; + + $inputDirectories[$i] = NaturalDocs::File->CanonizePath($inputDirectories[$i]); + + if (! -e $inputDirectories[$i] || ! -d $inputDirectories[$i]) + { push @errorMessages, 'The input directory ' . $inputDirectories[$i] . ' does not exist.'; }; + }; + } + else + { push @errorMessages, 'You did not specify an input (source) directory.'; }; + + if (defined $projectDirectory) + { + if (!NaturalDocs::File->PathIsAbsolute($projectDirectory)) + { $projectDirectory = NaturalDocs::File->JoinPaths(Cwd::cwd(), $projectDirectory, 1); }; + + $projectDirectory = NaturalDocs::File->CanonizePath($projectDirectory); + + if (! -e $projectDirectory || ! -d $projectDirectory) + { push @errorMessages, 'The project directory ' . $projectDirectory . ' does not exist.'; }; + + # Create the Data subdirectory if it doesn't exist. + NaturalDocs::File->CreatePath( NaturalDocs::File->JoinPaths($projectDirectory, 'Data', 1) ); + } + else + { push @errorMessages, 'You did not specify a project directory.'; }; + + + # Make sure the excluded input directories are canonized, and add the project and output directories to the list. + + for (my $i = 0; $i < scalar @excludedInputDirectories; $i++) + { + if (!NaturalDocs::File->PathIsAbsolute($excludedInputDirectories[$i])) + { $excludedInputDirectories[$i] = NaturalDocs::File->JoinPaths(Cwd::cwd(), $excludedInputDirectories[$i], 1); }; + + $excludedInputDirectories[$i] = NaturalDocs::File->CanonizePath($excludedInputDirectories[$i]); + }; + + push @excludedInputDirectories, $projectDirectory; + + foreach my $buildTarget (@buildTargets) + { + push @excludedInputDirectories, $buildTarget->Directory(); + }; + + + # Determine the tab length, and default to four if not specified. + + if (defined $tabLength) + { + if ($tabLength !~ /^[0-9]+$/) + { push @errorMessages, 'The tab length must be a number.'; }; + } + else + { $tabLength = 4; }; + + + # Strip any quotes off of the charset. + $charset =~ tr/\"//d; + + + # Exit with the error message if there was one. + + if (scalar @errorMessages) + { + print join("\n", @errorMessages) . "\nType NaturalDocs -h to see the syntax reference.\n"; + exit; + }; + }; + +# +# Function: PrintSyntax +# +# Prints the syntax reference. +# +sub PrintSyntax + { + my ($self) = @_; + + # Make sure all line lengths are under 80 characters. + + print + + "Natural Docs, version " . $self->TextAppVersion() . "\n" + . $self->AppURL() . "\n" + . "This program is licensed under the GPL\n" + . "--------------------------------------\n" + . "\n" + . "Syntax:\n" + . "\n" + . " NaturalDocs -i [input (source) directory]\n" + . " (-i [input (source) directory] ...)\n" + . " -o [output format] [output directory]\n" + . " (-o [output format] [output directory] ...)\n" + . " -p [project directory]\n" + . " [options]\n" + . "\n" + . "Examples:\n" + . "\n" + . " NaturalDocs -i C:\\My Project\\Source -o HTML C:\\My Project\\Docs\n" + . " -p C:\\My Project\\Natural Docs\n" + . " NaturalDocs -i /src/project -o HTML /doc/project\n" + . " -p /etc/naturaldocs/project -s Small -q\n" + . "\n" + . "Required Parameters:\n" + . "\n" + . " -i [dir]\n--input [dir]\n--source [dir]\n" + . " Specifies the input (source) directory. Required.\n" + . " Can be specified multiple times.\n" + . "\n" + . " -o [fmt] [dir]\n--output [fmt] [dir]\n" + . " Specifies the output format and directory. Required.\n" + . " Can be specified multiple times, but only once per directory.\n" + . " Possible output formats:\n"; + + $self->PrintOutputFormats(' - '); + + print + "\n" + . " -p [dir]\n--project [dir]\n" + . " Specifies the project directory. Required.\n" + . " There needs to be a unique project directory for every source directory.\n" + . "\n" + . "Optional Parameters:\n" + . "\n" + . " -s [style] ([style] [style] ...)\n--style [style] ([style] [style] ...)\n" + . " Specifies the CSS style when building HTML output. If multiple styles are\n" + . " specified, they will all be included in the order given.\n" + . "\n" + . " -do\n--documented-only\n" + . " Specifies only documented code aspects should be included in the output.\n" + . "\n" + . " -t [len]\n--tab-length [len]\n" + . " Specifies the number of spaces tabs should be expanded to. This only needs\n" + . " to be set if you use tabs in example code and text diagrams. Defaults to 4.\n" + . "\n" + . " -xi [dir]\n--exclude-input [dir]\n--exclude-source [dir]\n" + . " Excludes an input (source) directory from the documentation.\n" + . " Automatically done for the project and output directories. Can\n" + . " be specified multiple times.\n" + . "\n" + . " -nag\n--no-auto-group\n" + . " Turns off auto-grouping completely.\n" + . "\n" + . " -r\n--rebuild\n" + . " Rebuilds all output and data files from scratch.\n" + . " Does not affect the menu file.\n" + . "\n" + . " -ro\n--rebuild-output\n" + . " Rebuilds all output files from scratch.\n" + . "\n" + . " -q\n--quiet\n" + . " Suppresses all non-error output.\n" + . "\n" + . " -?\n -h\n--help\n" + . " Displays this syntax reference.\n"; + }; + + +# +# Function: PrintOutputFormats +# +# Prints all the possible output formats that can be specified with -o. Each one will be placed on its own line. +# +# Parameters: +# +# prefix - Characters to prefix each one with, such as for indentation. +# +sub PrintOutputFormats #(prefix) + { + my ($self, $prefix) = @_; + + my $outputPackages = NaturalDocs::Builder::OutputPackages(); + + foreach my $outputPackage (@$outputPackages) + { + print $prefix . $outputPackage->CommandLineOption() . "\n"; + }; + }; + + +# +# Function: LoadAndComparePreviousSettings +# +# Loads <PreviousSettings.nd> and compares the values there with those in the command line. If differences require it, +# sets <rebuildData> and/or <rebuildOutput>. +# +sub LoadAndComparePreviousSettings + { + my ($self) = @_; + + my $fileIsOkay = 1; + my $fileName = NaturalDocs::Project->PreviousSettingsFile(); + my $version; + + if (!open(PREVIOUS_SETTINGS_FILEHANDLE, '<' . $fileName)) + { $fileIsOkay = undef; } + else + { + # See if it's binary. + binmode(PREVIOUS_SETTINGS_FILEHANDLE); + + my $firstChar; + read(PREVIOUS_SETTINGS_FILEHANDLE, $firstChar, 1); + + if ($firstChar != ::BINARY_FORMAT()) + { + close(PREVIOUS_SETTINGS_FILEHANDLE); + $fileIsOkay = undef; + } + else + { + $version = NaturalDocs::Version->FromBinaryFile(\*PREVIOUS_SETTINGS_FILEHANDLE); + + # The file format changed in 1.33. + + if ($version > NaturalDocs::Settings->AppVersion() || $version < NaturalDocs::Version->FromString('1.33')) + { + close(PREVIOUS_SETTINGS_FILEHANDLE); + $fileIsOkay = undef; + }; + }; + }; + + + if (!$fileIsOkay) + { + # We need to reparse everything because --documented-only may have changed. + # We need to rebuild everything because --tab-length may have changed. + NaturalDocs::Project->ReparseEverything(); + NaturalDocs::Project->RebuildEverything(); + } + else + { + my $raw; + + # [UInt8: tab expansion] + # [UInt8: documented only (0 or 1)] + # [UInt8: no auto-group (0 or 1)] + # [AString16: charset] + + read(PREVIOUS_SETTINGS_FILEHANDLE, $raw, 5); + my ($prevTabLength, $prevDocumentedOnly, $prevNoAutoGroup, $prevCharsetLength) + = unpack('CCCn', $raw); + + if ($prevTabLength != $self->TabLength()) + { + # We need to rebuild all output because this affects all text diagrams. + NaturalDocs::Project->RebuildEverything(); + }; + + if ($prevDocumentedOnly == 0) + { $prevDocumentedOnly = undef; }; + if ($prevNoAutoGroup == 0) + { $prevNoAutoGroup = undef; }; + + if ($prevDocumentedOnly != $self->DocumentedOnly() || + $prevNoAutoGroup != $self->NoAutoGroup()) + { + NaturalDocs::Project->ReparseEverything(); + }; + + my $prevCharset; + read(PREVIOUS_SETTINGS_FILEHANDLE, $prevCharset, $prevCharsetLength); + + if ($prevCharset ne $charset) + { NaturalDocs::Project->RebuildEverything(); }; + + + # [UInt8: number of input directories] + + read(PREVIOUS_SETTINGS_FILEHANDLE, $raw, 1); + my $inputDirectoryCount = unpack('C', $raw); + + while ($inputDirectoryCount) + { + # [AString16: input directory] [AString16: input directory name] ... + + read(PREVIOUS_SETTINGS_FILEHANDLE, $raw, 2); + my $inputDirectoryLength = unpack('n', $raw); + + my $inputDirectory; + read(PREVIOUS_SETTINGS_FILEHANDLE, $inputDirectory, $inputDirectoryLength); + + read (PREVIOUS_SETTINGS_FILEHANDLE, $raw, 2); + my $inputDirectoryNameLength = unpack('n', $raw); + + my $inputDirectoryName; + read(PREVIOUS_SETTINGS_FILEHANDLE, $inputDirectoryName, $inputDirectoryNameLength); + + # Not doing anything with this for now. + + $inputDirectoryCount--; + }; + + + # [UInt8: number of output targets] + + read(PREVIOUS_SETTINGS_FILEHANDLE, $raw, 1); + my $outputTargetCount = unpack('C', $raw); + + # Keys are the directories, values are the command line options. + my %previousOutputDirectories; + + while ($outputTargetCount) + { + # [AString16: output directory] [AString16: output format command line option] ... + + read(PREVIOUS_SETTINGS_FILEHANDLE, $raw, 2); + my $outputDirectoryLength = unpack('n', $raw); + + my $outputDirectory; + read(PREVIOUS_SETTINGS_FILEHANDLE, $outputDirectory, $outputDirectoryLength); + + read (PREVIOUS_SETTINGS_FILEHANDLE, $raw, 2); + my $outputCommandLength = unpack('n', $raw); + + my $outputCommand; + read(PREVIOUS_SETTINGS_FILEHANDLE, $outputCommand, $outputCommandLength); + + $previousOutputDirectories{$outputDirectory} = $outputCommand; + + $outputTargetCount--; + }; + + # Check if any targets were added to the command line, or if their formats changed. We don't care if targets were + # removed. + my $buildTargets = $self->BuildTargets(); + + foreach my $buildTarget (@$buildTargets) + { + if (!exists $previousOutputDirectories{$buildTarget->Directory()} || + $buildTarget->Builder()->CommandLineOption() ne $previousOutputDirectories{$buildTarget->Directory()}) + { + NaturalDocs::Project->RebuildEverything(); + last; + }; + }; + + close(PREVIOUSSTATEFILEHANDLE); + }; + }; + + +# +# Function: SavePreviousSettings +# +# Saves the settings into <PreviousSettings.nd>. +# +sub SavePreviousSettings + { + my ($self) = @_; + + open (PREVIOUS_SETTINGS_FILEHANDLE, '>' . NaturalDocs::Project->PreviousSettingsFile()) + or die "Couldn't save " . NaturalDocs::Project->PreviousSettingsFile() . ".\n"; + + binmode(PREVIOUS_SETTINGS_FILEHANDLE); + + print PREVIOUS_SETTINGS_FILEHANDLE '' . ::BINARY_FORMAT(); + NaturalDocs::Version->ToBinaryFile(\*PREVIOUS_SETTINGS_FILEHANDLE, NaturalDocs::Settings->AppVersion()); + + # [UInt8: tab length] + # [UInt8: documented only (0 or 1)] + # [UInt8: no auto-group (0 or 1)] + # [AString16: charset] + # [UInt8: number of input directories] + + my $inputDirectories = $self->InputDirectories(); + + print PREVIOUS_SETTINGS_FILEHANDLE pack('CCCnA*C', $self->TabLength(), ($self->DocumentedOnly() ? 1 : 0), + ($self->NoAutoGroup() ? 1 : 0), length($charset), $charset, + scalar @$inputDirectories); + + foreach my $inputDirectory (@$inputDirectories) + { + my $inputDirectoryName = $self->InputDirectoryNameOf($inputDirectory); + + # [AString16: input directory] [AString16: input directory name] ... + print PREVIOUS_SETTINGS_FILEHANDLE pack('nA*nA*', length($inputDirectory), $inputDirectory, + length($inputDirectoryName), $inputDirectoryName); + }; + + # [UInt8: number of output targets] + + my $buildTargets = $self->BuildTargets(); + print PREVIOUS_SETTINGS_FILEHANDLE pack('C', scalar @$buildTargets); + + foreach my $buildTarget (@$buildTargets) + { + my $buildTargetDirectory = $buildTarget->Directory(); + my $buildTargetCommand = $buildTarget->Builder()->CommandLineOption(); + + # [AString16: output directory] [AString16: output format command line option] ... + print PREVIOUS_SETTINGS_FILEHANDLE pack('nA*nA*', length($buildTargetDirectory), $buildTargetDirectory, + length($buildTargetCommand), $buildTargetCommand); + }; + + close(PREVIOUS_SETTINGS_FILEHANDLE); + }; + + +1; |