public/ITextParsers.h
author Scott Ehlert <ds@alliedmods.net>
Wed Aug 15 06:19:30 2007 +0000 (2007-08-15)
changeset 1330 ab94316bb52b
parent 1226 478550a4d5ec
child 1406 f5c07ec3c052
permissions -rw-r--r--
Updated license headers on virtually all files with extremely minor changes in the name of some sort of strange consistency.
All plugin and include file headers also have been changed to say about GPL3 instead of GPL2.

(This day shall henceforth be known as the Eighty Column Massacre of '07)
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2007 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 	 * The INI file format is defined as:
    46 	 * WHITESPACE: 0x20, \n, \t, \r
    47 	 * IDENTIFIER: A-Z a-z 0-9 _ - , + . $ ? / 
    48 	 * STRING: Any set of symbols
    49 	 * 
    50 	 * Basic syntax is comprised of SECTIONs.
    51 	 * A SECTION is defined as:
    52 	 * [SECTIONNAME]
    53 	 * OPTION
    54 	 * OPTION
    55 	 * OPTION...
    56 	 *
    57 	 * SECTIONNAME is an IDENTIFIER.
    58 	 * OPTION can be repeated any number of times, once per line.
    59 	 * OPTION is defined as one of:
    60 	 *  KEY = "VALUE"
    61 	 *  KEY = VALUE
    62 	 *  KEY
    63 	 * Where KEY is an IDENTIFIER and VALUE is a STRING.
    64 	 * 
    65 	 * WHITESPACE should always be omitted.
    66 	 * COMMENTS should be stripped, and are defined as text occurring in:
    67 	 * ;<TEXT>
    68 	 * 
    69 	 * Example file below.  Note that
    70 	 * The second line is technically invalid.  The event handler
    71 	 * must decide whether this should be allowed.
    72 	 * --FILE BELOW--
    73 	 * [gaben]
    74 	 * hi = clams
    75 	 * bye = "NO CLAMS"
    76 	 *
    77 	 * [valve]
    78 	 * cannot
    79 	 * maintain
    80 	 * products
    81 	 */
    82 
    83 	/**
    84 	 * @brief Contains parse events for INI files.
    85 	 */
    86 	class ITextListener_INI
    87 	{
    88 	public:
    89 		/**
    90 		 * @brief Called when a new section is encountered in an INI file.
    91 		 * 
    92 		 * @param section		Name of section in between the [ and ] characters.
    93 		 * @param invalid_tokens True if invalid tokens were detected in the name.
    94 		 * @param close_bracket	True if a closing bracket was detected, false otherwise.
    95 		 * @param extra_tokens	True if extra tokens were detected on the line.
    96 		 * @param curtok		Contains current token in the line where the section name starts.
    97 		 *						You can add to this offset when failing to point to a token.
    98 		 * @return				True to keep parsing, false otherwise.
    99 		 */
   100 		virtual bool ReadINI_NewSection(const char *section,
   101 										bool invalid_tokens,
   102 										bool close_bracket,
   103 										bool extra_tokens,
   104 										unsigned int *curtok)
   105 		{
   106 			return true;
   107 		}
   108 
   109 		/**
   110 		 * @brief Called when encountering a key/value pair in an INI file.
   111 		 * 
   112 		 * @param key			Name of key.
   113 		 * @param value			String containing value (with quotes stripped, if any).
   114 		 * @param invalid_tokens Whether or not the key contained invalid tokens.
   115 		 * @param equal_token	There was an '=' sign present (in case the value is missing).
   116 		 * @param quotes		Whether value was enclosed in quotes.
   117 		 * @param curtok		Contains the token index of the start of the value string.  
   118 		 *						This can be changed when returning false.
   119 		 * @return				True to keep parsing, false otherwise.
   120 		 */
   121 		virtual bool ReadINI_KeyValue(const char *key, 
   122 									  const char *value, 
   123 									  bool invalid_tokens,
   124 									  bool equal_token,
   125 									  bool quotes,
   126 									  unsigned int *curtok)
   127 		{
   128 			return true;
   129 		}
   130 
   131 		/**
   132 		 * @brief Called after a line has been preprocessed, if it has text.
   133 		 *
   134 		 * @param line			Contents of line.
   135 		 * @param curtok		Pointer to optionally store failed position in string.
   136 		 * @return				True to keep parsing, false otherwise.
   137 		 */
   138 		virtual bool ReadINI_RawLine(const char *line, unsigned int *curtok)
   139 		{
   140 			return true;
   141 		}
   142 	};
   143 
   144 	/**
   145 	 * :TODO: write this in CFG (context free grammar) format so it makes sense
   146 	 * 
   147 	 * The SMC file format is defined as:
   148 	 * WHITESPACE: 0x20, \n, \t, \r
   149 	 * IDENTIFIER: Any ASCII character EXCLUDING ", {, }, ;, //, / *, or WHITESPACE.
   150 	 * STRING: Any set of symbols enclosed in quotes.
   151 	 * Note: if a STRING does not have quotes, it is parsed as an IDENTIFIER.
   152 	 *
   153 	 * Basic syntax is comprised of SECTIONBLOCKs.
   154 	 * A SECTIONBLOCK defined as:
   155 	 *
   156 	 * SECTIONNAME
   157 	 * {
   158 	 *    OPTION
   159 	 * }
   160 	 * 
   161 	 * OPTION can be repeated any number of times inside a SECTIONBLOCK.
   162 	 * A new line will terminate an OPTION, but there can be more than one OPTION per line.
   163 	 * OPTION is defined any of:
   164 	 * 	  "KEY"  "VALUE"
   165 	 *    SECTIONBLOCK
   166 	 *
   167 	 * SECTIONNAME, KEY, VALUE, and SINGLEKEY are strings
   168 	 * SECTIONNAME cannot have trailing characters if quoted, but the quotes can be optionally removed.
   169 	 * If SECTIONNAME is not enclosed in quotes, the entire sectionname string is used (minus surrounding whitespace).
   170 	 * If KEY is not enclosed in quotes, the key is terminated at first whitespace.
   171 	 * If VALUE is not properly enclosed in quotes, the entire value string is used (minus surrounding whitespace).
   172 	 * The VALUE may have inner quotes, but the key string may not.
   173 	 *
   174 	 * For an example, see configs/permissions.cfg
   175 	 *
   176 	 * WHITESPACE should be ignored.
   177 	 * Comments are text occurring inside the following tokens, and should be stripped
   178 	 * unless they are inside literal strings:
   179 	 *  ;<TEXT>
   180 	 *  //<TEXT>
   181 	 *  / *<TEXT> */
   182 
   183 	/**
   184 	 * @brief Lists actions to take when an SMC parse hook is done.
   185 	 */
   186 	enum SMCParseResult
   187 	{
   188 		SMCParse_Continue,		/**< Continue parsing */
   189 		SMCParse_Halt,			/**< Stop parsing here */
   190 		SMCParse_HaltFail		/**< Stop parsing and return SMCParseError_Custom */
   191 	};
   192 
   193 	/**
   194 	 * @brief Lists error codes possible from parsing an SMC file.
   195 	 */
   196 	enum SMCParseError
   197 	{
   198 		SMCParse_Okay = 0,			/**< No error */
   199 		SMCParse_StreamOpen,		/**< Stream failed to open */
   200 		SMCParse_StreamError,		/**< The stream died... somehow */
   201 		SMCParse_Custom,			/**< A custom handler threw an error */
   202 		SMCParse_InvalidSection1,	/**< A section was declared without quotes, and had extra tokens */
   203 		SMCParse_InvalidSection2,	/**< A section was declared without any header */
   204 		SMCParse_InvalidSection3,	/**< A section ending was declared with too many unknown tokens */
   205 		SMCParse_InvalidSection4,	/**< A section ending has no matching beginning */
   206 		SMCParse_InvalidSection5,	/**< A section beginning has no matching ending */
   207 		SMCParse_InvalidTokens,		/**< There were too many unidentifiable strings on one line */
   208 		SMCParse_TokenOverflow,		/**< The token buffer overflowed */
   209 		SMCParse_InvalidProperty1,	/**< A property was declared outside of any section */
   210 	};
   211 
   212 	/**
   213 	 * @brief Describes the events available for reading an SMC stream.
   214 	 */
   215 	class ITextListener_SMC
   216 	{
   217 	public:
   218 		/**
   219 		 * @brief Called when starting parsing.
   220 		 */
   221 		virtual void ReadSMC_ParseStart()
   222 		{
   223 		};
   224 
   225 		/**
   226 		 * @brief Called when ending parsing.
   227 		 *
   228 		 * @param halted			True if abnormally halted, false otherwise.
   229 		 * @param failed			True if parsing failed, false otherwise.
   230 		 */
   231 		virtual void ReadSMC_ParseEnd(bool halted, bool failed)
   232 		{
   233 		}
   234 
   235 		/**
   236 		 * @brief Called when a warning occurs.
   237 		 * @param error				By-reference variable containing the error message of the warning.
   238 		 * @param tokens			Pointer to the token stream causing the error.
   239 		 * @return					SMCParseResult directive.
   240 		 */
   241 		virtual SMCParseResult ReadSMC_OnWarning(SMCParseError &error, const char *tokens)
   242 		{
   243 			return SMCParse_HaltFail;
   244 		}
   245 
   246 		/**
   247 		 * @brief Called when entering a new section
   248 		 *
   249 		 * @param name			Name of section, with the colon omitted.
   250 		 * @param opt_quotes	Whether or not the option string was enclosed in quotes.
   251 		 * @return				SMCParseResult directive.
   252 		 */
   253 		virtual SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes)
   254 		{
   255 			return SMCParse_Continue;
   256 		}
   257 
   258 		/**
   259 		 * @brief Called when encountering a key/value pair in a section.
   260 		 * 
   261 		 * @param key			Key string.
   262 		 * @param value			Value string.  If no quotes were specified, this will be NULL, 
   263 								and key will contain the entire string.
   264 		 * @param key_quotes	Whether or not the key was in quotation marks.
   265 		 * @param value_quotes	Whether or not the value was in quotation marks.
   266 		 * @return				SMCParseResult directive.
   267 		 */
   268 		virtual SMCParseResult ReadSMC_KeyValue(const char *key, 
   269 												const char *value, 
   270 												bool key_quotes, 
   271 												bool value_quotes)
   272 		{
   273 			return SMCParse_Continue;
   274 		}
   275 
   276 		/**
   277 		 * @brief Called when leaving the current section.
   278 		 *
   279 		 * @return				SMCParseResult directive.
   280 		 */
   281 		virtual SMCParseResult ReadSMC_LeavingSection()
   282 		{
   283 			return SMCParse_Continue;
   284 		}
   285 
   286 		/**
   287 		 * @brief Called after an input line has been preprocessed.
   288 		 *
   289 		 * @param line			String containing line input.
   290 		 * @param curline		Number of line in file.
   291 		 * @return				SMCParseResult directive.
   292 		 */
   293 		virtual SMCParseResult ReadSMC_RawLine(const char *line, unsigned int curline)
   294 		{
   295 			return SMCParse_Continue;
   296 		}
   297 	};	
   298 
   299 	#define SMINTERFACE_TEXTPARSERS_NAME		"ITextParsers"
   300 	#define SMINTERFACE_TEXTPARSERS_VERSION		1
   301 
   302 	/**
   303 	 * @brief Contains various text stream parsing functions.
   304 	 */
   305 	class ITextParsers : public SMInterface
   306 	{
   307 	public:
   308 		virtual const char *GetInterfaceName()
   309 		{
   310 			return SMINTERFACE_TEXTPARSERS_NAME;
   311 		}
   312 		virtual unsigned int GetInterfaceVersion()
   313 		{
   314 			return SMINTERFACE_TEXTPARSERS_VERSION;
   315 		}
   316 	public:
   317 		/**
   318 		 * @brief Parses an INI-format file.
   319 		 *
   320 		 * @param file			Path to file.
   321 		 * @param ini_listener	Event handler for reading file.
   322 		 * @param line			If non-NULL, will contain last line parsed (0 if file could not be opened).
   323 		 * @param col			If non-NULL, will contain last column parsed (undefined if file could not be opened).
   324 		 * @return				True if parsing succeeded, false if file couldn't be opened or there was a syntax error.
   325 		 */
   326 		virtual bool ParseFile_INI(const char *file, 
   327 									ITextListener_INI *ini_listener,
   328 									unsigned int *line,
   329 									unsigned int *col) =0;
   330 
   331 		/**
   332 		 * @brief Parses an SMC-format text file.
   333 		 * Note that the parser makes every effort to obey broken syntax.
   334 		 * For example, if an open brace is missing, but the section name has a colon,
   335 		 * it will let you know.  It is up to the event handlers to decide whether to be strict or not.
   336 		 *
   337 		 * @param file			Path to file.
   338 		 * @param smc_listener	Event handler for reading file.
   339 		 * @param line			If non-NULL, will contain last line parsed (0 if file could not be opened).
   340 		 * @param col			If non-NULL, will contain last column parsed (undefined if file could not be opened).
   341 		 * @return				An SMCParseError result code.
   342 		 */
   343 		virtual SMCParseError ParseFile_SMC(const char *file, 
   344 									ITextListener_SMC *smc_listener, 
   345 									unsigned int *line, 
   346 									unsigned int *col) =0;
   347 
   348 		/**
   349 		 * @brief Converts an SMCParseError to a string.
   350 		 *
   351 		 * @param err			SMCParseError.
   352 		 * @return				String error message, or NULL if none.
   353 		 */
   354 		virtual const char *GetSMCErrorString(SMCParseError err) =0;
   355 
   356 	public:
   357 		/**
   358 		 * @brief Returns the number of bytes that a multi-byte character contains in a UTF-8 stream.
   359 		 * If the current character is not multi-byte, the function returns 1.
   360 		 *
   361 		 * @param stream		Pointer to multi-byte ANSI character string.
   362 		 * @return				Number of bytes in current character.
   363 		 */
   364 		virtual unsigned int GetUTF8CharBytes(const char *stream) =0;
   365 	};
   366 }
   367 
   368 #endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_