2009-04-19 18:07:22 +00:00
#region = = = = = = = = = = = = = = = = = = Copyright ( c ) 2007 Pascal vd Heiden
/ *
* Copyright ( c ) 2007 Pascal vd Heiden , www . codeimp . com
* This program is released under GNU General Public License
*
* 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 .
*
* /
#endregion
#region = = = = = = = = = = = = = = = = = = Namespaces
using System ;
using System.Collections ;
using System.Collections.Generic ;
2014-05-13 09:43:58 +00:00
using System.IO ;
2009-04-19 18:07:22 +00:00
using CodeImp.DoomBuilder.IO ;
2016-01-27 14:08:15 +00:00
using ScintillaNET ;
2009-04-19 18:07:22 +00:00
#endregion
namespace CodeImp.DoomBuilder.Config
{
2014-07-11 10:13:26 +00:00
//mxd
2016-02-22 08:04:06 +00:00
public enum ScriptType
2015-03-26 11:30:36 +00:00
{
2016-04-13 14:11:35 +00:00
UNKNOWN ,
ACS ,
MODELDEF ,
DECORATE ,
GLDEFS ,
SNDSEQ ,
MAPINFO ,
VOXELDEF ,
TEXTURES ,
ANIMDEFS ,
REVERBS ,
TERRAIN ,
X11R6RGB ,
CVARINFO ,
2016-05-24 22:11:29 +00:00
SNDINFO ,
2016-07-14 23:39:48 +00:00
LOCKDEFS ,
2016-11-24 11:55:11 +00:00
MENUDEF ,
SBARINFO ,
USDF ,
2016-12-12 12:35:18 +00:00
GAMEINFO ,
KEYCONF ,
FONTDEFS ,
2017-01-15 22:00:45 +00:00
ZSCRIPT ,
2020-10-11 20:36:07 +00:00
DECALDEF ,
2014-07-11 10:13:26 +00:00
}
2009-04-19 18:07:22 +00:00
internal class ScriptConfiguration : IComparable < ScriptConfiguration >
{
#region = = = = = = = = = = = = = = = = = = Constants
#endregion
#region = = = = = = = = = = = = = = = = = = Variables
// Compiler settings
2014-05-13 09:43:58 +00:00
private readonly CompilerInfo compiler ;
private readonly string parameters ;
private readonly string resultlump ;
2009-04-19 18:07:22 +00:00
// Editor settings
2014-05-13 09:43:58 +00:00
private readonly string description ;
private readonly int codepage ;
2016-03-14 13:41:26 +00:00
private readonly string extrawordchars ; //mxd. Extra characters to be threated as part of a word by Scintilla
2014-05-13 09:43:58 +00:00
private readonly string [ ] extensions ;
private readonly bool casesensitive ;
private readonly int insertcase ;
2016-01-27 14:08:15 +00:00
private readonly Lexer lexer ;
2014-05-13 09:43:58 +00:00
private readonly string keywordhelp ;
private readonly string functionopen ;
private readonly string functionclose ;
2016-01-27 14:08:15 +00:00
private readonly string codeblockopen ; //mxd
private readonly string codeblockclose ; //mxd
private readonly string arrayopen ; //mxd
private readonly string arrayclose ; //mxd
2014-05-13 09:43:58 +00:00
private readonly string argumentdelimiter ;
private readonly string terminator ;
2014-07-11 10:13:26 +00:00
private readonly ScriptType scripttype ; //mxd
2009-04-19 18:07:22 +00:00
// Collections
2014-05-13 09:43:58 +00:00
private readonly Dictionary < string , string > keywords ;
private readonly Dictionary < string , string > lowerkeywords ;
2016-01-27 14:08:15 +00:00
private readonly List < string > keywordkeyssorted ; //mxd
2014-05-13 09:43:58 +00:00
private readonly List < string > constants ;
private readonly Dictionary < string , string > lowerconstants ;
2016-02-06 21:23:43 +00:00
private readonly List < string > properties ; //mxd
private readonly Dictionary < string , string > lowerproperties ; //mxd
2014-05-13 09:43:58 +00:00
private readonly Dictionary < string , string [ ] > snippets ; //mxd
2016-01-27 14:08:15 +00:00
private readonly HashSet < string > snippetkeyssorted ; //mxd
private readonly HashSet < char > braces ; //mxd
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Properties
// Compiler settings
public CompilerInfo Compiler { get { return compiler ; } }
public string Parameters { get { return parameters ; } }
public string ResultLump { get { return resultlump ; } }
// Editor settings
public string Description { get { return description ; } }
public int CodePage { get { return codepage ; } }
public string [ ] Extensions { get { return extensions ; } }
public bool CaseSensitive { get { return casesensitive ; } }
public int InsertCase { get { return insertcase ; } }
2016-01-27 14:08:15 +00:00
public Lexer Lexer { get { return lexer ; } }
2009-04-19 18:07:22 +00:00
public string KeywordHelp { get { return keywordhelp ; } }
public string FunctionOpen { get { return functionopen ; } }
public string FunctionClose { get { return functionclose ; } }
2016-01-27 14:08:15 +00:00
public string CodeBlockOpen { get { return codeblockopen ; } } //mxd
public string CodeBlockClose { get { return codeblockclose ; } } //mxd
public string ArrayOpen { get { return arrayopen ; } } //mxd
public string ArrayClose { get { return arrayclose ; } } //mxd
2009-04-19 18:07:22 +00:00
public string ArgumentDelimiter { get { return argumentdelimiter ; } }
public string Terminator { get { return terminator ; } }
2016-03-14 13:41:26 +00:00
public string ExtraWordCharacters { get { return extrawordchars ; } } //mxd
2014-07-11 10:13:26 +00:00
public ScriptType ScriptType { get { return scripttype ; } } //mxd
2014-05-13 09:43:58 +00:00
2009-04-19 18:07:22 +00:00
// Collections
2016-01-27 14:08:15 +00:00
public ICollection < string > Keywords { get { return keywordkeyssorted ; } }
2016-02-06 21:23:43 +00:00
public ICollection < string > Properties { get { return properties ; } } //mxd
2009-04-19 18:07:22 +00:00
public ICollection < string > Constants { get { return constants ; } }
2016-02-06 21:23:43 +00:00
public ICollection < string > Snippets { get { return snippetkeyssorted ; } } //mxd
2016-01-27 14:08:15 +00:00
public HashSet < char > BraceChars { get { return braces ; } } //mxd
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Constructor / Disposer
// This creates the default script configuration
// that is used for documents of unknown type
internal ScriptConfiguration ( )
{
// Initialize
2014-02-26 14:11:06 +00:00
this . keywords = new Dictionary < string , string > ( StringComparer . Ordinal ) ;
2009-04-19 18:07:22 +00:00
this . constants = new List < string > ( ) ;
2016-02-06 21:23:43 +00:00
this . properties = new List < string > ( ) ; //mxd
2014-02-26 14:11:06 +00:00
this . lowerkeywords = new Dictionary < string , string > ( StringComparer . Ordinal ) ;
this . lowerconstants = new Dictionary < string , string > ( StringComparer . Ordinal ) ;
2016-02-06 21:23:43 +00:00
this . lowerproperties = new Dictionary < string , string > ( StringComparer . Ordinal ) ; //mxd
2016-01-27 14:08:15 +00:00
this . keywordkeyssorted = new List < string > ( ) ; //mxd
this . snippets = new Dictionary < string , string [ ] > ( StringComparer . OrdinalIgnoreCase ) ; //mxd
this . snippetkeyssorted = new HashSet < string > ( ) ; //mxd
this . braces = new HashSet < char > ( ) ; //mxd
2009-04-19 18:07:22 +00:00
// Settings
2016-01-27 14:08:15 +00:00
lexer = Lexer . Null ;
2009-04-19 18:07:22 +00:00
casesensitive = false ;
codepage = 65001 ;
parameters = "" ;
resultlump = "" ;
insertcase = 0 ;
keywordhelp = "" ;
functionopen = "" ;
functionclose = "" ;
2016-01-27 14:08:15 +00:00
codeblockopen = "" ; //mxd
codeblockclose = "" ; //mxd
arrayopen = "" ; //mxd
arrayclose = "" ; //mxd
2009-04-19 18:07:22 +00:00
argumentdelimiter = "" ;
terminator = "" ;
description = "Plain text" ;
2014-07-11 10:13:26 +00:00
scripttype = ScriptType . UNKNOWN ; //mxd
2016-03-14 13:41:26 +00:00
extrawordchars = "" ; //mxd
2014-02-26 14:11:06 +00:00
extensions = new [ ] { "txt" } ;
2009-04-19 18:07:22 +00:00
}
// Constructor
internal ScriptConfiguration ( Configuration cfg )
{
// Initialize
2014-02-26 14:11:06 +00:00
this . keywords = new Dictionary < string , string > ( StringComparer . Ordinal ) ;
2009-04-19 18:07:22 +00:00
this . constants = new List < string > ( ) ;
2016-02-06 21:23:43 +00:00
this . properties = new List < string > ( ) ; //mxd
2014-02-26 14:11:06 +00:00
this . lowerkeywords = new Dictionary < string , string > ( StringComparer . Ordinal ) ;
this . lowerconstants = new Dictionary < string , string > ( StringComparer . Ordinal ) ;
2016-02-06 21:23:43 +00:00
this . lowerproperties = new Dictionary < string , string > ( StringComparer . Ordinal ) ; //mxd
2016-01-27 14:08:15 +00:00
this . keywordkeyssorted = new List < string > ( ) ; //mxd
this . snippets = new Dictionary < string , string [ ] > ( StringComparer . OrdinalIgnoreCase ) ; //mxd
this . snippetkeyssorted = new HashSet < string > ( ) ; //mxd
this . braces = new HashSet < char > ( ) ; //mxd
2009-04-19 18:07:22 +00:00
// Read settings
description = cfg . ReadSetting ( "description" , "Untitled script" ) ;
codepage = cfg . ReadSetting ( "codepage" , 0 ) ;
2014-02-26 14:11:06 +00:00
string extensionsstring = cfg . ReadSetting ( "extensions" , "" ) ;
string compilername = cfg . ReadSetting ( "compiler" , "" ) ;
2009-04-19 18:07:22 +00:00
parameters = cfg . ReadSetting ( "parameters" , "" ) ;
resultlump = cfg . ReadSetting ( "resultlump" , "" ) ;
casesensitive = cfg . ReadSetting ( "casesensitive" , true ) ;
insertcase = cfg . ReadSetting ( "insertcase" , 0 ) ;
2016-01-27 14:08:15 +00:00
lexer = ( Lexer ) cfg . ReadSetting ( "lexer" , ( int ) Lexer . Container ) ;
2009-04-19 18:07:22 +00:00
keywordhelp = cfg . ReadSetting ( "keywordhelp" , "" ) ;
functionopen = cfg . ReadSetting ( "functionopen" , "" ) ;
functionclose = cfg . ReadSetting ( "functionclose" , "" ) ;
2016-01-27 14:08:15 +00:00
codeblockopen = cfg . ReadSetting ( "codeblockopen" , "" ) ; //mxd
codeblockclose = cfg . ReadSetting ( "codeblockclose" , "" ) ; //mxd
arrayopen = cfg . ReadSetting ( "arrayopen" , "" ) ; //mxd
arrayclose = cfg . ReadSetting ( "arrayclose" , "" ) ; //mxd
2009-04-19 18:07:22 +00:00
argumentdelimiter = cfg . ReadSetting ( "argumentdelimiter" , "" ) ;
terminator = cfg . ReadSetting ( "terminator" , "" ) ;
2016-03-14 13:41:26 +00:00
extrawordchars = cfg . ReadSetting ( "extrawordchars" , "" ) ; //mxd
2016-01-27 14:08:15 +00:00
2017-02-09 00:26:25 +00:00
//mxd. Get script type...
2016-11-24 11:55:11 +00:00
string scripttypestr = cfg . ReadSetting ( "scripttype" , string . Empty ) ;
if ( ! string . IsNullOrEmpty ( scripttypestr ) )
{
List < string > typenames = new List < string > ( Enum . GetNames ( typeof ( ScriptType ) ) ) ;
int pos = typenames . IndexOf ( scripttypestr . ToUpperInvariant ( ) ) ;
if ( pos = = - 1 )
{
scripttype = ScriptType . UNKNOWN ;
General . ErrorLogger . Add ( ErrorType . Warning , "Unknown script type \"" + scripttypestr . ToUpperInvariant ( ) + "\" in \"" + description + "\" script configuration." ) ;
}
else
{
scripttype = ( ScriptType ) pos ;
}
}
else
{
scripttype = ScriptType . UNKNOWN ;
}
2017-02-09 00:26:25 +00:00
//mxd. Make braces array
if ( ! string . IsNullOrEmpty ( functionopen ) ) braces . Add ( functionopen [ 0 ] ) ;
2016-01-27 14:08:15 +00:00
if ( ! string . IsNullOrEmpty ( functionclose ) ) braces . Add ( functionclose [ 0 ] ) ;
if ( ! string . IsNullOrEmpty ( codeblockopen ) ) braces . Add ( codeblockopen [ 0 ] ) ;
if ( ! string . IsNullOrEmpty ( codeblockclose ) ) braces . Add ( codeblockclose [ 0 ] ) ;
if ( ! string . IsNullOrEmpty ( arrayopen ) ) braces . Add ( arrayopen [ 0 ] ) ;
if ( ! string . IsNullOrEmpty ( arrayclose ) ) braces . Add ( arrayclose [ 0 ] ) ;
2009-04-19 18:07:22 +00:00
// Make extensions array
extensions = extensionsstring . Split ( ',' ) ;
for ( int i = 0 ; i < extensions . Length ; i + + ) extensions [ i ] = extensions [ i ] . Trim ( ) ;
// Load keywords
2014-02-26 14:11:06 +00:00
IDictionary dic = cfg . ReadSetting ( "keywords" , new Hashtable ( ) ) ;
2009-04-19 18:07:22 +00:00
foreach ( DictionaryEntry de in dic )
{
2016-02-06 21:23:43 +00:00
string keyword = de . Key . ToString ( ) ;
if ( keywords . ContainsKey ( keyword ) ) //mxd
{
2016-02-22 08:04:06 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , "Keyword \"" + keyword + "\" is double defined in \"" + description + "\" script configuration." ) ;
2016-02-06 21:23:43 +00:00
continue ;
}
keywords [ keyword ] = de . Value . ToString ( ) ;
lowerkeywords [ keyword . ToLowerInvariant ( ) ] = keyword ;
keywordkeyssorted . Add ( keyword ) ; //mxd
2009-04-19 18:07:22 +00:00
}
2016-01-27 14:08:15 +00:00
//mxd. Sort keywords lookup
keywordkeyssorted . Sort ( ) ;
2016-02-06 21:23:43 +00:00
//mxd. Load properties
dic = cfg . ReadSetting ( "properties" , new Hashtable ( ) ) ;
foreach ( DictionaryEntry de in dic )
{
string property = de . Key . ToString ( ) ;
if ( lowerproperties . ContainsValue ( property ) ) //mxd
{
2016-02-22 08:04:06 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , "Property \"" + property + "\" is double defined in \"" + description + "\" script configuration." ) ;
2016-02-06 21:23:43 +00:00
continue ;
}
properties . Add ( property ) ;
lowerproperties [ property . ToLowerInvariant ( ) ] = property ;
}
//mxd
properties . Sort ( ) ;
2009-04-19 18:07:22 +00:00
// Load constants
dic = cfg . ReadSetting ( "constants" , new Hashtable ( ) ) ;
foreach ( DictionaryEntry de in dic )
{
2016-02-06 21:23:43 +00:00
string constant = de . Key . ToString ( ) ;
if ( lowerconstants . ContainsValue ( constant ) ) //mxd
{
2016-02-22 08:04:06 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , "Constant \"" + constant + "\" is double defined in \"" + description + "\" script configuration." ) ;
2016-02-06 21:23:43 +00:00
continue ;
}
constants . Add ( constant ) ;
lowerconstants [ constant . ToLowerInvariant ( ) ] = constant ;
2009-04-19 18:07:22 +00:00
}
2016-01-27 14:08:15 +00:00
//mxd
constants . Sort ( ) ;
2014-05-13 09:43:58 +00:00
//mxd. Load Snippets
string snippetsdir = cfg . ReadSetting ( "snippetsdir" , "" ) ;
2016-01-27 14:08:15 +00:00
if ( ! string . IsNullOrEmpty ( snippetsdir ) )
2014-12-03 23:15:26 +00:00
{
2014-05-13 09:43:58 +00:00
string snippetspath = Path . Combine ( General . SnippetsPath , snippetsdir ) ;
2016-01-27 14:08:15 +00:00
if ( Directory . Exists ( snippetspath ) )
2014-12-03 23:15:26 +00:00
{
2014-05-13 09:43:58 +00:00
string [ ] files = Directory . GetFiles ( snippetspath , "*.txt" , SearchOption . TopDirectoryOnly ) ;
2016-01-27 14:08:15 +00:00
List < string > sortedkeys = new List < string > ( ) ;
2014-05-13 09:43:58 +00:00
2016-01-27 14:08:15 +00:00
foreach ( string file in files )
2014-12-03 23:15:26 +00:00
{
2014-05-13 09:43:58 +00:00
string name = Path . GetFileNameWithoutExtension ( file ) ;
2016-01-27 14:08:15 +00:00
if ( string . IsNullOrEmpty ( name ) )
2014-12-03 23:15:26 +00:00
{
2016-02-22 08:04:06 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , "Failed to load snippet \"" + file + "\" for \"" + description + "\" script configuration." ) ;
2016-01-27 14:08:15 +00:00
}
else
2014-12-03 23:15:26 +00:00
{
2016-01-27 14:08:15 +00:00
if ( name . Contains ( " " ) ) name = name . Replace ( ' ' , '_' ) ;
2014-05-13 09:43:58 +00:00
string [ ] lines = File . ReadAllLines ( file ) ;
2016-01-27 14:08:15 +00:00
if ( lines . Length > 0 )
2014-12-03 23:15:26 +00:00
{
2014-05-13 09:43:58 +00:00
snippets . Add ( name , lines ) ;
2016-01-27 14:08:15 +00:00
sortedkeys . Add ( name ) ;
}
else
2014-12-03 23:15:26 +00:00
{
2016-02-22 08:04:06 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , "Failed to load snippet \"" + file + "\" for \"" + description + "\" script configuration: file is empty!" ) ;
2014-05-13 09:43:58 +00:00
}
}
}
2016-01-27 14:08:15 +00:00
//mxd. Sort snippets lookup
sortedkeys . Sort ( ) ;
snippetkeyssorted = new HashSet < string > ( sortedkeys , StringComparer . OrdinalIgnoreCase ) ;
}
}
// Compiler specified?
if ( compilername . Length > 0 )
{
// Find compiler
foreach ( CompilerInfo c in General . Compilers )
{
// Compiler name matches?
if ( c . Name = = compilername )
{
// Apply compiler
this . compiler = c ;
break ;
}
2014-05-13 09:43:58 +00:00
}
2016-01-27 14:08:15 +00:00
// No compiler found?
2016-02-22 08:04:06 +00:00
if ( this . compiler = = null ) throw new Exception ( "Compiler \"" + compilername + "\" is not defined" ) ;
2014-05-13 09:43:58 +00:00
}
2009-04-19 18:07:22 +00:00
}
#endregion
#region = = = = = = = = = = = = = = = = = = Methods
// This returns the correct case for a keyword
// Returns the same keyword as the input when it cannot be found
public string GetKeywordCase ( string keyword )
{
if ( lowerkeywords . ContainsKey ( keyword . ToLowerInvariant ( ) ) )
return lowerkeywords [ keyword . ToLowerInvariant ( ) ] ;
else
return keyword ;
}
// This returns the correct case for a constant
// Returns the same constant as the input when it cannot be found
public string GetConstantCase ( string constant )
{
if ( lowerconstants . ContainsKey ( constant . ToLowerInvariant ( ) ) )
return lowerconstants [ constant . ToLowerInvariant ( ) ] ;
else
return constant ;
}
// This returns true when the given word is a keyword
public bool IsKeyword ( string keyword )
{
return lowerkeywords . ContainsKey ( keyword . ToLowerInvariant ( ) ) ;
}
// This returns true when the given word is a contant
public bool IsConstant ( string constant )
{
return lowerconstants . ContainsKey ( constant . ToLowerInvariant ( ) ) ;
}
// This returns the function definition for a keyword
// Returns null when no function definition exists
// NOTE: The keyword parameter is case-sensitive!
public string GetFunctionDefinition ( string keyword )
{
if ( keywords . ContainsKey ( keyword ) )
return keywords [ keyword ] ;
else
return null ;
}
2016-01-27 14:08:15 +00:00
//mxd
public string [ ] GetSnippet ( string name )
{
return ( snippetkeyssorted . Contains ( name ) ? snippets [ name ] : null ) ;
}
2009-04-19 18:07:22 +00:00
// This sorts by description
public int CompareTo ( ScriptConfiguration other )
{
return string . Compare ( this . description , other . description , true ) ;
}
2014-07-11 10:13:26 +00:00
//mxd
public override string ToString ( )
{
return description ;
}
2009-04-19 18:07:22 +00:00
#endregion
}
}