public/ITextParsers.h
author Nicholas Hastings <skamonkey@gmail.com>
Wed Aug 14 14:20:57 2013 -0400 (2013-08-14)
changeset 4008 490b01aa0683
parent 2558 178d7954939d
permissions -rw-r--r--
Updated some CS:GO gamedata.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #ifndef _INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_
    33 #define _INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_
    34 
    35 /**
    36  * @file ITextParsers.h
    37  * @brief Defines various text/file parsing functions, as well as UTF-8 support code.
    38  */
    39 
    40 #include <IShareSys.h>
    41 
    42 namespace SourceMod
    43 {
    44 
    45 	#define SMINTERFACE_TEXTPARSERS_NAME		"ITextParsers"
    46 	#define SMINTERFACE_TEXTPARSERS_VERSION		4
    47 
    48 	/**
    49 	 * The INI file format is defined as:
    50 	 * WHITESPACE: 0x20, \n, \t, \r
    51 	 * IDENTIFIER: A-Z a-z 0-9 _ - , + . $ ? / 
    52 	 * STRING: Any set of symbols
    53 	 * 
    54 	 * Basic syntax is comprised of SECTIONs.
    55 	 * A SECTION is defined as:
    56 	 * [SECTIONNAME]
    57 	 * OPTION
    58 	 * OPTION
    59 	 * OPTION...
    60 	 *
    61 	 * SECTIONNAME is an IDENTIFIER.
    62 	 * OPTION can be repeated any number of times, once per line.
    63 	 * OPTION is defined as one of:
    64 	 *  KEY = "VALUE"
    65 	 *  KEY = VALUE
    66 	 *  KEY
    67 	 * Where KEY is an IDENTIFIER and VALUE is a STRING.
    68 	 * 
    69 	 * WHITESPACE should always be omitted.
    70 	 * COMMENTS should be stripped, and are defined as text occurring in:
    71 	 * ;<TEXT>
    72 	 * 
    73 	 * Example file below.  Note that
    74 	 * The second line is technically invalid.  The event handler
    75 	 * must decide whether this should be allowed.
    76 	 * --FILE BELOW--
    77 	 * [gaben]
    78 	 * hi = clams
    79 	 * bye = "NO CLAMS"
    80 	 *
    81 	 * [valve]
    82 	 * cannot
    83 	 * maintain
    84 	 * products
    85 	 */
    86 
    87 	/**
    88 	 * @brief Contains parse events for INI files.
    89 	 */
    90 	class ITextListener_INI
    91 	{
    92 	public:
    93 		/** 
    94 		 * @brief Returns version number.
    95 		 */
    96 		virtual unsigned int GetTextParserVersion1()
    97 		{
    98 			return SMINTERFACE_TEXTPARSERS_VERSION;
    99 		}
   100 	public:
   101 		/**
   102 		 * @brief Called when a new section is encountered in an INI file.
   103 		 * 
   104 		 * @param section		Name of section in between the [ and ] characters.
   105 		 * @param invalid_tokens True if invalid tokens were detected in the name.
   106 		 * @param close_bracket	True if a closing bracket was detected, false otherwise.
   107 		 * @param extra_tokens	True if extra tokens were detected on the line.
   108 		 * @param curtok		Contains current token in the line where the section name starts.
   109 		 *						You can add to this offset when failing to point to a token.
   110 		 * @return				True to keep parsing, false otherwise.
   111 		 */
   112 		virtual bool ReadINI_NewSection(const char *section,
   113 										bool invalid_tokens,
   114 										bool close_bracket,
   115 										bool extra_tokens,
   116 										unsigned int *curtok)
   117 		{
   118 			return true;
   119 		}
   120 
   121 		/**
   122 		 * @brief Called when encountering a key/value pair in an INI file.
   123 		 * 
   124 		 * @param key			Name of key.
   125 		 * @param value			String containing value (with quotes stripped, if any).
   126 		 * @param invalid_tokens Whether or not the key contained invalid tokens.
   127 		 * @param equal_token	There was an '=' sign present (in case the value is missing).
   128 		 * @param quotes		Whether value was enclosed in quotes.
   129 		 * @param curtok		Contains the token index of the start of the value string.  
   130 		 *						This can be changed when returning false.
   131 		 * @return				True to keep parsing, false otherwise.
   132 		 */
   133 		virtual bool ReadINI_KeyValue(const char *key, 
   134 									  const char *value, 
   135 									  bool invalid_tokens,
   136 									  bool equal_token,
   137 									  bool quotes,
   138 									  unsigned int *curtok)
   139 		{
   140 			return true;
   141 		}
   142 
   143 		/**
   144 		 * @brief Called after a line has been preprocessed, if it has text.
   145 		 *
   146 		 * @param line			Contents of line.
   147 		 * @param curtok		Pointer to optionally store failed position in string.
   148 		 * @return				True to keep parsing, false otherwise.
   149 		 */
   150 		virtual bool ReadINI_RawLine(const char *line, unsigned int *curtok)
   151 		{
   152 			return true;
   153 		}
   154 	};
   155 
   156 	/**
   157 	 * :TODO: write this in CFG (context free grammar) format so it makes sense
   158 	 * 
   159 	 * The SMC file format is defined as:
   160 	 * WHITESPACE: 0x20, \n, \t, \r
   161 	 * IDENTIFIER: Any ASCII character EXCLUDING ", {, }, ;, //, / *, or WHITESPACE.
   162 	 * STRING: Any set of symbols enclosed in quotes.
   163 	 * Note: if a STRING does not have quotes, it is parsed as an IDENTIFIER.
   164 	 *
   165 	 * Basic syntax is comprised of SECTIONBLOCKs.
   166 	 * A SECTIONBLOCK defined as:
   167 	 *
   168 	 * SECTIONNAME
   169 	 * {
   170 	 *    OPTION
   171 	 * }
   172 	 * 
   173 	 * OPTION can be repeated any number of times inside a SECTIONBLOCK.
   174 	 * A new line will terminate an OPTION, but there can be more than one OPTION per line.
   175 	 * OPTION is defined any of:
   176 	 * 	  "KEY"  "VALUE"
   177 	 *    SECTIONBLOCK
   178 	 *
   179 	 * SECTIONNAME, KEY, VALUE, and SINGLEKEY are strings
   180 	 * SECTIONNAME cannot have trailing characters if quoted, but the quotes can be optionally removed.
   181 	 * If SECTIONNAME is not enclosed in quotes, the entire sectionname string is used (minus surrounding whitespace).
   182 	 * If KEY is not enclosed in quotes, the key is terminated at first whitespace.
   183 	 * If VALUE is not properly enclosed in quotes, the entire value string is used (minus surrounding whitespace).
   184 	 * The VALUE may have inner quotes, but the key string may not.
   185 	 *
   186 	 * For an example, see configs/permissions.cfg
   187 	 *
   188 	 * WHITESPACE should be ignored.
   189 	 * Comments are text occurring inside the following tokens, and should be stripped
   190 	 * unless they are inside literal strings:
   191 	 *  ;<TEXT>
   192 	 *  //<TEXT>
   193 	 *  / *<TEXT> */
   194 
   195 	/**
   196 	 * @brief Lists actions to take when an SMC parse hook is done.
   197 	 */
   198 	enum SMCResult
   199 	{
   200 		SMCResult_Continue,		/**< Continue parsing */
   201 		SMCResult_Halt,			/**< Stop parsing here */
   202 		SMCResult_HaltFail		/**< Stop parsing and return SMCError_Custom */
   203 	};
   204 
   205 	/**
   206 	 * @brief Lists error codes possible from parsing an SMC file.
   207 	 */
   208 	enum SMCError
   209 	{
   210 		SMCError_Okay = 0,			/**< No error */
   211 		SMCError_StreamOpen,		/**< Stream failed to open */
   212 		SMCError_StreamError,		/**< The stream died... somehow */
   213 		SMCError_Custom,			/**< A custom handler threw an error */
   214 		SMCError_InvalidSection1,	/**< A section was declared without quotes, and had extra tokens */
   215 		SMCError_InvalidSection2,	/**< A section was declared without any header */
   216 		SMCError_InvalidSection3,	/**< A section ending was declared with too many unknown tokens */
   217 		SMCError_InvalidSection4,	/**< A section ending has no matching beginning */
   218 		SMCError_InvalidSection5,	/**< A section beginning has no matching ending */
   219 		SMCError_InvalidTokens,		/**< There were too many unidentifiable strings on one line */
   220 		SMCError_TokenOverflow,		/**< The token buffer overflowed */
   221 		SMCError_InvalidProperty1,	/**< A property was declared outside of any section */
   222 	};
   223 
   224 	/**
   225 	 * @brief States for line/column
   226 	 */
   227 	struct SMCStates
   228 	{
   229 		unsigned int line;			/**< Current line */
   230 		unsigned int col;			/**< Current col */
   231 	};
   232 
   233 	/**
   234 	 * @brief Describes the events available for reading an SMC stream.
   235 	 */
   236 	class ITextListener_SMC
   237 	{
   238 	public:
   239 		/** 
   240 		 * @brief Returns version number.
   241 		 */
   242 		virtual unsigned int GetTextParserVersion2()
   243 		{
   244 			return SMINTERFACE_TEXTPARSERS_VERSION;
   245 		}
   246 	public:
   247 		/**
   248 		 * @brief Called when starting parsing.
   249 		 */
   250 		virtual void ReadSMC_ParseStart()
   251 		{
   252 		};
   253 
   254 		/**
   255 		 * @brief Called when ending parsing.
   256 		 *
   257 		 * @param halted			True if abnormally halted, false otherwise.
   258 		 * @param failed			True if parsing failed, false otherwise.
   259 		 */
   260 		virtual void ReadSMC_ParseEnd(bool halted, bool failed)
   261 		{
   262 		}
   263 
   264 		/**
   265 		 * @brief Called when entering a new section
   266 		 *
   267 		 * @param states		Parsing states.
   268 		 * @param name			Name of section, with the colon omitted.
   269 		 * @return				SMCResult directive.
   270 		 */
   271 		virtual SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name)
   272 		{
   273 			return SMCResult_Continue;
   274 		}
   275 
   276 		/**
   277 		 * @brief Called when encountering a key/value pair in a section.
   278 		 * 
   279 		 * @param states		Parsing states.
   280 		 * @param key			Key string.
   281 		 * @param value			Value string.  If no quotes were specified, this will be NULL, 
   282 		 *						and key will contain the entire string.
   283 		 * @return				SMCResult directive.
   284 		 */
   285 		virtual SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
   286 		{
   287 			return SMCResult_Continue;
   288 		}
   289 
   290 		/**
   291 		 * @brief Called when leaving the current section.
   292 		 *
   293 		 * @param states		Parsing states.
   294 		 * @return				SMCResult directive.
   295 		 */
   296 		virtual SMCResult ReadSMC_LeavingSection(const SMCStates *states)
   297 		{
   298 			return SMCResult_Continue;
   299 		}
   300 
   301 		/**
   302 		 * @brief Called after an input line has been preprocessed.
   303 		 *
   304 		 * @param states		Parsing states.
   305 		 * @param line			Contents of the line, null terminated at the position 
   306 		 * 						of the newline character (thus, no newline will exist).
   307 		 * @return				SMCResult directive.
   308 		 */
   309 		virtual SMCResult ReadSMC_RawLine(const SMCStates *states, const char *line)
   310 		{
   311 			return SMCResult_Continue;
   312 		}
   313 	};	
   314 
   315 	/**
   316 	 * @brief Contains various text stream parsing functions.
   317 	 */
   318 	class ITextParsers : public SMInterface
   319 	{
   320 	public:
   321 		virtual const char *GetInterfaceName()
   322 		{
   323 			return SMINTERFACE_TEXTPARSERS_NAME;
   324 		}
   325 		virtual unsigned int GetInterfaceVersion()
   326 		{
   327 			return SMINTERFACE_TEXTPARSERS_VERSION;
   328 		}
   329 		virtual bool IsVersionCompatible(unsigned int version)
   330 		{
   331 			if (version < 2)
   332 			{
   333 				return false;
   334 			}
   335 			return SMInterface::IsVersionCompatible(version);
   336 		}
   337 	public:
   338 		/**
   339 		 * @brief Parses an INI-format file.
   340 		 *
   341 		 * @param file			Path to file.
   342 		 * @param ini_listener	Event handler for reading file.
   343 		 * @param line			If non-NULL, will contain last line parsed (0 if file could not be opened).
   344 		 * @param col			If non-NULL, will contain last column parsed (undefined if file could not be opened).
   345 		 * @return				True if parsing succeeded, false if file couldn't be opened or there was a syntax error.
   346 		 */
   347 		virtual bool ParseFile_INI(const char *file, 
   348 									ITextListener_INI *ini_listener,
   349 									unsigned int *line,
   350 									unsigned int *col) =0;
   351 
   352 		/**
   353 		 * @brief Parses an SMC-format text file.
   354 		 * Note that the parser makes every effort to obey broken syntax.
   355 		 * For example, if an open brace is missing, but the section name has a colon,
   356 		 * it will let you know.  It is up to the event handlers to decide whether to be strict or not.
   357 		 *
   358 		 * @param file			Path to file.
   359 		 * @param smc_listener	Event handler for reading file.
   360 		 * @param states		Optional pointer to store last known states.
   361 		 * @return				An SMCError result code.
   362 		 */
   363 		virtual SMCError ParseFile_SMC(const char *file, 
   364 									ITextListener_SMC *smc_listener, 
   365 									SMCStates *states) =0;
   366 
   367 		/**
   368 		 * @brief Converts an SMCError to a string.
   369 		 *
   370 		 * @param err			SMCError.
   371 		 * @return				String error message, or NULL if none.
   372 		 */
   373 		virtual const char *GetSMCErrorString(SMCError err) =0;
   374 
   375 	public:
   376 		/**
   377 		 * @brief Returns the number of bytes that a multi-byte character contains in a UTF-8 stream.
   378 		 * If the current character is not multi-byte, the function returns 1.
   379 		 *
   380 		 * @param stream		Pointer to multi-byte ANSI character string.
   381 		 * @return				Number of bytes in current character.
   382 		 */
   383 		virtual unsigned int GetUTF8CharBytes(const char *stream) =0;
   384 
   385 		/**
   386 		 * @brief Returns whether the first multi-byte character in the given stream
   387 		 * is a whitespace character.
   388 		 *
   389 		 * @param stream		Pointer to multi-byte character string.
   390 		 * @return				True if first character is whitespace, false otherwise.
   391 		 */
   392 		virtual bool IsWhitespace(const char *stream) =0;
   393 
   394 		/**
   395 		 * @brief Same as ParseFile_SMC, but with an extended error buffer.
   396 		 *
   397 		 * @param file			Path to file.
   398 		 * @param smc_listener	Event handler for reading file.
   399 		 * @param states		Optional pointer to store last known states.
   400 		 * @param buffer		Error message buffer.
   401 		 * @param maxsize		Maximum size of the error buffer.
   402 		 * @return 				Error code.
   403 		 */
   404 		virtual SMCError ParseSMCFile(const char *file,
   405 			ITextListener_SMC *smc_listener,
   406 			SMCStates *states,
   407 			char *buffer,
   408 			size_t maxsize) =0;
   409 
   410 		/**
   411 		 * @brief Parses a raw UTF8 stream as an SMC file.
   412 		 *
   413 		 * @param stream		Memory containing data.
   414 		 * @param length		Number of bytes in the stream.
   415 		 * @param smc_listener	Event handler for reading file.
   416 		 * @param states		Optional pointer to store last known states.
   417 		 * @param buffer		Error message buffer.
   418 		 * @param maxsize		Maximum size of the error buffer.
   419 		 * @return 				Error code.
   420 		 */
   421 		virtual SMCError ParseSMCStream(const char *stream,
   422 			size_t length,
   423 			ITextListener_SMC *smc_listener,
   424 			SMCStates *states,
   425 			char *buffer,
   426 			size_t maxsize) =0;
   427 	};
   428 
   429 	inline unsigned int _GetUTF8CharBytes(const char *stream)
   430 	{
   431 		unsigned char c = *(unsigned char *)stream;
   432 		if (c & (1<<7))
   433 		{
   434 			if (c & (1<<5))
   435 			{
   436 				if (c & (1<<4))
   437 				{
   438 					return 4;
   439 				}
   440 				return 3;
   441 			}
   442 			return 2;
   443 		}
   444 		return 1;
   445 	}
   446 }
   447 
   448 extern SourceMod::ITextParsers *textparsers;
   449 
   450 #endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_
   451