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