core/CTextParsers.cpp
author David Anderson <dvander@alliedmods.net>
Wed Nov 08 06:30:20 2006 +0000 (2006-11-08)
changeset 159 43c471413f70
parent 150 42d85020e6ea
child 197 dd30d3d6a51f
permissions -rw-r--r--
finalized new structure and imported newly proposed plugin system API
added zlib to source tree
added VM API to source tree
dvander@145
     1
#include <stdio.h>
dvander@145
     2
#include <ctype.h>
dvander@150
     3
#include <wctype.h>
dvander@145
     4
#include <string.h>
dvander@150
     5
#include <stdlib.h>
dvander@145
     6
#include "CTextParsers.h"
dvander@145
     7
dvander@145
     8
CTextParsers g_TextParse;
dvander@145
     9
dvander@145
    10
static int g_ini_chartable1[255] = {0};
dvander@150
    11
static int g_ws_chartable[255] = {0};
dvander@145
    12
dvander@145
    13
CTextParsers::CTextParsers()
dvander@145
    14
{
dvander@145
    15
	g_ini_chartable1['_'] = 1;
dvander@145
    16
	g_ini_chartable1['-'] = 1;
dvander@145
    17
	g_ini_chartable1[','] = 1;
dvander@145
    18
	g_ini_chartable1['+'] = 1;
dvander@145
    19
	g_ini_chartable1['.'] = 1;
dvander@145
    20
	g_ini_chartable1['$'] = 1;
dvander@145
    21
	g_ini_chartable1['?'] = 1;
dvander@145
    22
	g_ini_chartable1['/'] = 1;
dvander@150
    23
	g_ws_chartable['\n'] = 1;
dvander@150
    24
	g_ws_chartable['\v'] = 1;
dvander@150
    25
	g_ws_chartable['\r'] = 1;
dvander@150
    26
	g_ws_chartable['\t'] = 1;
dvander@150
    27
	g_ws_chartable['\f'] = 1;
dvander@150
    28
	g_ws_chartable[' '] = 1;
dvander@150
    29
}
dvander@150
    30
dvander@150
    31
unsigned int CTextParsers::GetUTF8CharBytes(const char *stream)
dvander@150
    32
{
dvander@150
    33
	return _GetUTF8CharBytes(stream);
dvander@145
    34
}
dvander@145
    35
dvander@159
    36
bool CTextParsers::ParseFile_SMC(const char *file, ITextListener_SMC *smc_listener, unsigned int *line, unsigned int *col, bool strict)
dvander@145
    37
{
dvander@159
    38
	/* This beast is a lot more rigorous than our INI friend. */
dvander@145
    39
dvander@145
    40
	return false;
dvander@145
    41
}
dvander@145
    42
dvander@145
    43
bool CTextParsers::ParseFile_INI(const char *file, ITextListener_INI *ini_listener, unsigned int *line, unsigned int *col)
dvander@145
    44
{
dvander@145
    45
	FILE *fp = fopen(file, "rt");
dvander@145
    46
	unsigned int curline = 0;
dvander@145
    47
	unsigned int curtok;
dvander@145
    48
	size_t len;
dvander@145
    49
dvander@145
    50
	if (!fp)
dvander@145
    51
	{
dvander@145
    52
		if (line)
dvander@145
    53
		{
dvander@145
    54
			*line = 0;
dvander@145
    55
		}
dvander@145
    56
dvander@145
    57
		return false;
dvander@145
    58
	}
dvander@145
    59
dvander@145
    60
	char buffer[2048];
dvander@145
    61
	char *ptr, *save_ptr;
dvander@145
    62
	bool in_quote;
dvander@150
    63
dvander@145
    64
	while (!feof(fp))
dvander@145
    65
	{
dvander@145
    66
		curline++;
dvander@145
    67
		curtok = 0;
dvander@145
    68
		buffer[0] = '\0';
dvander@145
    69
		if (fgets(buffer, sizeof(buffer), fp) == NULL)
dvander@145
    70
		{
dvander@145
    71
			break;
dvander@145
    72
		}
dvander@150
    73
dvander@150
    74
		//:TODO: this will only run once, so find a nice way to move it out of the while loop
dvander@150
    75
		/* If this is the first line, check the first three bytes for BOM */
dvander@150
    76
		if (curline == 1 && 
dvander@150
    77
			buffer[0] == (char)0xEF && 
dvander@150
    78
			buffer[1] == (char)0xBB && 
dvander@150
    79
			buffer[2] == (char)0xBF)
dvander@150
    80
		{
dvander@150
    81
			/* We have a UTF-8 marked file... skip these bytes */
dvander@150
    82
			ptr = &buffer[3];
dvander@150
    83
		} else {
dvander@150
    84
			ptr = buffer;
dvander@150
    85
		}
dvander@150
    86
dvander@150
    87
		/***************************************************
dvander@150
    88
		 * We preprocess the string before parsing tokens! *
dvander@150
    89
		 ***************************************************/
dvander@150
    90
dvander@145
    91
		/* First strip beginning whitespace */
dvander@150
    92
		while (*ptr != '\0' && g_ws_chartable[*ptr] != 0)
dvander@145
    93
		{
dvander@145
    94
			ptr++;
dvander@145
    95
		}
dvander@145
    96
dvander@145
    97
		len = strlen(ptr);
dvander@145
    98
dvander@145
    99
		if (!len)
dvander@145
   100
		{
dvander@145
   101
			continue;
dvander@145
   102
		}
dvander@145
   103
dvander@145
   104
		/* Now search for comment characters */
dvander@145
   105
		in_quote = false;
dvander@145
   106
		save_ptr = ptr;
dvander@145
   107
		for (size_t i=0; i<len; i++,ptr++)
dvander@145
   108
		{
dvander@145
   109
			if (!in_quote)
dvander@145
   110
			{
dvander@145
   111
				switch (*ptr)
dvander@145
   112
				{
dvander@145
   113
				case '"':
dvander@145
   114
					{
dvander@145
   115
						in_quote = true;
dvander@145
   116
						break;
dvander@145
   117
					}
dvander@145
   118
				case ';':
dvander@145
   119
					{
dvander@145
   120
						/* Stop the loop */
dvander@145
   121
						len = i;
dvander@145
   122
						/* Terminate the string here */
dvander@145
   123
						*ptr = '\0';
dvander@145
   124
						break;
dvander@145
   125
					}
dvander@145
   126
				}
dvander@145
   127
			} else {
dvander@145
   128
				if (*ptr == '"')
dvander@145
   129
				{
dvander@145
   130
					in_quote = false;
dvander@145
   131
				}
dvander@145
   132
			}
dvander@145
   133
		}
dvander@145
   134
dvander@145
   135
		if (!len)
dvander@145
   136
		{
dvander@145
   137
			continue;
dvander@145
   138
		}
dvander@145
   139
dvander@145
   140
		ptr = save_ptr;
dvander@145
   141
dvander@145
   142
		/* Lastly, strip ending whitespace off */
dvander@145
   143
		for (size_t i=len-1; i>=0 && i<len; i--)
dvander@145
   144
		{
dvander@150
   145
			if (g_ws_chartable[ptr[i]])
dvander@145
   146
			{
dvander@145
   147
				ptr[i] = '\0';
dvander@145
   148
				len--;
dvander@145
   149
			} else {
dvander@145
   150
				break;
dvander@145
   151
			}
dvander@145
   152
		}
dvander@145
   153
dvander@145
   154
		if (!len)
dvander@145
   155
		{
dvander@145
   156
			continue;
dvander@145
   157
		}
dvander@145
   158
dvander@145
   159
		if (!ini_listener->ReadINI_RawLine(ptr, &curtok))
dvander@145
   160
		{
dvander@145
   161
			goto event_failed;
dvander@145
   162
		}
dvander@145
   163
dvander@145
   164
		if (*ptr == '[')
dvander@145
   165
		{
dvander@145
   166
			bool invalid_tokens = false;
dvander@145
   167
			bool got_bracket = false;
dvander@145
   168
			bool extra_tokens = false;
dvander@145
   169
			char c;
dvander@150
   170
			bool alnum;
dvander@150
   171
			wchar_t wc;
dvander@145
   172
dvander@145
   173
			for (size_t i=1; i<len; i++)
dvander@145
   174
			{
dvander@145
   175
				c = ptr[i];
dvander@150
   176
				alnum = false;
dvander@150
   177
dvander@150
   178
				if (c & (1<<7))
dvander@150
   179
				{
dvander@150
   180
					if (mbtowc(&wc, &ptr[i], len-i) != -1)
dvander@150
   181
					{
dvander@150
   182
						alnum = (iswalnum(wc) != 0);
dvander@150
   183
						i += _GetUTF8CharBytes(&ptr[i]) - 1;
dvander@150
   184
					}
dvander@150
   185
				} else {
dvander@150
   186
					alnum = (isalnum(c) != 0) || (g_ini_chartable1[c] != 0);
dvander@150
   187
				}
dvander@150
   188
				if (!alnum)
dvander@145
   189
				{
dvander@145
   190
					/* First check - is this a bracket? */
dvander@145
   191
					if (c == ']')
dvander@145
   192
					{
dvander@145
   193
						/* Yes! */
dvander@145
   194
						got_bracket = true;
dvander@145
   195
						/* If this isn't the last character... */
dvander@145
   196
						if (i != len - 1)
dvander@145
   197
						{
dvander@145
   198
							extra_tokens = true;
dvander@145
   199
						}
dvander@145
   200
						/* terminate */
dvander@145
   201
						ptr[i] = '\0';
dvander@145
   202
						break;
dvander@145
   203
					} else {
dvander@145
   204
						/* n...No! Continue copying. */
dvander@145
   205
						invalid_tokens = true;
dvander@145
   206
					}
dvander@145
   207
				}
dvander@145
   208
			}
dvander@145
   209
dvander@145
   210
			/* Tell the handler */
dvander@145
   211
			if (!ini_listener->ReadINI_NewSection(&ptr[1], invalid_tokens, got_bracket, extra_tokens, &curtok))
dvander@145
   212
			{
dvander@145
   213
				goto event_failed;
dvander@145
   214
			}
dvander@145
   215
		} else {
dvander@145
   216
			char *key_ptr = ptr;
dvander@145
   217
			char *val_ptr = NULL;
dvander@145
   218
			char c;
dvander@145
   219
			size_t first_space = 0;
dvander@145
   220
			bool invalid_tokens = false;
dvander@145
   221
			bool equal_token = false;
dvander@145
   222
			bool quotes = false;
dvander@150
   223
			bool alnum;
dvander@150
   224
			wchar_t wc;
dvander@150
   225
dvander@145
   226
			for (size_t i=0; i<len; i++)
dvander@145
   227
			{
dvander@145
   228
				c = ptr[i];
dvander@150
   229
				alnum = false;
dvander@145
   230
				/* is this an invalid char? */
dvander@150
   231
				if (c & (1<<7))
dvander@145
   232
				{
dvander@150
   233
					if (mbtowc(&wc, &ptr[i], len-i) != -1)
dvander@150
   234
					{
dvander@150
   235
						alnum = (iswalnum(wc) != 0);
dvander@150
   236
						i += _GetUTF8CharBytes(&ptr[i]) - 1;
dvander@150
   237
					}
dvander@150
   238
				} else {
dvander@150
   239
					alnum = (isalnum(c) != 0) || (g_ini_chartable1[c] != 0);
dvander@150
   240
				}
dvander@150
   241
dvander@150
   242
				if (!alnum)
dvander@150
   243
				{
dvander@150
   244
					if (g_ws_chartable[c])
dvander@145
   245
					{
dvander@159
   246
						/* if it's a space, keep track of the first occurring space */
dvander@145
   247
						if (!first_space)
dvander@145
   248
						{
dvander@145
   249
							first_space = i;
dvander@145
   250
						}
dvander@145
   251
					} else {
dvander@145
   252
						if (c == '=')
dvander@145
   253
						{
dvander@145
   254
							/* if it's an equal sign, we're done with the key */
dvander@145
   255
							if (first_space)
dvander@145
   256
							{
dvander@145
   257
								/* remove excess whitespace */
dvander@145
   258
								key_ptr[first_space] = '\0';
dvander@145
   259
							} else {
dvander@145
   260
								/* remove the equal sign */
dvander@145
   261
								key_ptr[i] = '\0';
dvander@145
   262
							}
dvander@145
   263
							if (ptr[++i] != '\0')
dvander@145
   264
							{
dvander@145
   265
								/* If this isn't the end, set next pointer */
dvander@145
   266
								val_ptr = &ptr[i];
dvander@145
   267
							}
dvander@145
   268
							equal_token = true;
dvander@145
   269
							break;
dvander@145
   270
						} else {
dvander@145
   271
							/* Mark that we got something invalid! */
dvander@145
   272
							invalid_tokens = true;
dvander@145
   273
							first_space = 0;
dvander@145
   274
						}
dvander@145
   275
					}
dvander@145
   276
				}
dvander@145
   277
			}
dvander@145
   278
dvander@145
   279
			/* Now we need to parse the value, if any */
dvander@145
   280
			if (val_ptr)
dvander@145
   281
			{
dvander@145
   282
				/* eat up spaces! there shouldn't be any h*/
dvander@150
   283
				while ((*val_ptr != '\0') && g_ws_chartable[*val_ptr] != 0)
dvander@145
   284
				{
dvander@145
   285
					val_ptr++;
dvander@145
   286
				}
dvander@145
   287
				if (*val_ptr == '\0')
dvander@145
   288
				{
dvander@145
   289
					val_ptr = NULL;
dvander@145
   290
					goto skip_value;
dvander@145
   291
				}
dvander@145
   292
				/* Do we have an initial quote? If so, the parsing rules change! */
dvander@145
   293
				if (*val_ptr == '"' && *val_ptr != '\0')
dvander@145
   294
				{
dvander@145
   295
					len = strlen(val_ptr);
dvander@145
   296
					if (val_ptr[len-1] == '"')
dvander@145
   297
					{
dvander@145
   298
						/* Strip quotes! */
dvander@145
   299
						val_ptr[--len] = '\0';
dvander@145
   300
						val_ptr++;
dvander@145
   301
						quotes = true;
dvander@145
   302
					}
dvander@145
   303
				}
dvander@145
   304
			}
dvander@145
   305
skip_value:
dvander@145
   306
			/* We're done! */
dvander@145
   307
			curtok = val_ptr - buffer;
dvander@145
   308
			if (!ini_listener->ReadINI_KeyValue(key_ptr, val_ptr, invalid_tokens, equal_token, quotes, &curtok))
dvander@145
   309
			{
dvander@145
   310
				curtok = 0;
dvander@145
   311
				goto event_failed;
dvander@145
   312
			}
dvander@145
   313
		}
dvander@145
   314
	}
dvander@145
   315
dvander@145
   316
	if (line)
dvander@145
   317
	{
dvander@145
   318
		*line = curline;
dvander@145
   319
	}
dvander@145
   320
dvander@145
   321
	fclose(fp);
dvander@145
   322
dvander@145
   323
	return true;
dvander@145
   324
dvander@145
   325
event_failed:
dvander@145
   326
	if (line)
dvander@145
   327
	{
dvander@145
   328
		*line = curline;
dvander@145
   329
	}
dvander@145
   330
dvander@145
   331
	if (col)
dvander@145
   332
	{
dvander@145
   333
		*col = curtok;
dvander@145
   334
	}
dvander@145
   335
dvander@145
   336
	fclose(fp);
dvander@145
   337
dvander@145
   338
	return false;
dvander@145
   339
}