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