core/CTextParsers.cpp
author David Anderson <dvander@alliedmods.net>
Mon Nov 06 10:57:37 2006 +0000 (2006-11-06)
changeset 145 473df5b9878e
child 150 42d85020e6ea
permissions -rw-r--r--
renamed mm_api, I don't like short names!
finished and tested the INI parser and its API
dvander@145
     1
#include <stdio.h>
dvander@145
     2
#include <ctype.h>
dvander@145
     3
#include <string.h>
dvander@145
     4
#include "CTextParsers.h"
dvander@145
     5
dvander@145
     6
CTextParsers g_TextParse;
dvander@145
     7
dvander@145
     8
static int g_ini_chartable1[255] = {0};
dvander@145
     9
dvander@145
    10
CTextParsers::CTextParsers()
dvander@145
    11
{
dvander@145
    12
	g_ini_chartable1['_'] = 1;
dvander@145
    13
	g_ini_chartable1['-'] = 1;
dvander@145
    14
	g_ini_chartable1[','] = 1;
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
}
dvander@145
    21
dvander@145
    22
bool CTextParsers::ParseFile_SMC(const char *file, ITextListener_SMC *smc_listener, unsigned int *line, unsigned int *col)
dvander@145
    23
{
dvander@145
    24
	/* :TODO: Implement this */
dvander@145
    25
	if (line)
dvander@145
    26
	{
dvander@145
    27
		*line = 0;
dvander@145
    28
	}
dvander@145
    29
dvander@145
    30
	return false;
dvander@145
    31
}
dvander@145
    32
dvander@145
    33
bool CTextParsers::ParseFile_INI(const char *file, ITextListener_INI *ini_listener, unsigned int *line, unsigned int *col)
dvander@145
    34
{
dvander@145
    35
	FILE *fp = fopen(file, "rt");
dvander@145
    36
	unsigned int curline = 0;
dvander@145
    37
	unsigned int curtok;
dvander@145
    38
	size_t len;
dvander@145
    39
dvander@145
    40
	if (!fp)
dvander@145
    41
	{
dvander@145
    42
		if (line)
dvander@145
    43
		{
dvander@145
    44
			*line = 0;
dvander@145
    45
		}
dvander@145
    46
dvander@145
    47
		return false;
dvander@145
    48
	}
dvander@145
    49
dvander@145
    50
	char buffer[2048];
dvander@145
    51
	char *ptr, *save_ptr;
dvander@145
    52
	bool in_quote;
dvander@145
    53
	while (!feof(fp))
dvander@145
    54
	{
dvander@145
    55
		curline++;
dvander@145
    56
		curtok = 0;
dvander@145
    57
		buffer[0] = '\0';
dvander@145
    58
		if (fgets(buffer, sizeof(buffer), fp) == NULL)
dvander@145
    59
		{
dvander@145
    60
			break;
dvander@145
    61
		}
dvander@145
    62
		
dvander@145
    63
		/* Preprocess the string before anything */
dvander@145
    64
		ptr = buffer;
dvander@145
    65
		
dvander@145
    66
		/* First strip beginning whitespace */
dvander@145
    67
		while ((*ptr != '\0') && isspace(*ptr))
dvander@145
    68
		{
dvander@145
    69
			ptr++;
dvander@145
    70
		}
dvander@145
    71
dvander@145
    72
		len = strlen(ptr);
dvander@145
    73
dvander@145
    74
		if (!len)
dvander@145
    75
		{
dvander@145
    76
			continue;
dvander@145
    77
		}
dvander@145
    78
dvander@145
    79
		/* Now search for comment characters */
dvander@145
    80
		in_quote = false;
dvander@145
    81
		save_ptr = ptr;
dvander@145
    82
		for (size_t i=0; i<len; i++,ptr++)
dvander@145
    83
		{
dvander@145
    84
			if (!in_quote)
dvander@145
    85
			{
dvander@145
    86
				switch (*ptr)
dvander@145
    87
				{
dvander@145
    88
				case '"':
dvander@145
    89
					{
dvander@145
    90
						in_quote = true;
dvander@145
    91
						break;
dvander@145
    92
					}
dvander@145
    93
				case ';':
dvander@145
    94
					{
dvander@145
    95
						/* Stop the loop */
dvander@145
    96
						len = i;
dvander@145
    97
						/* Terminate the string here */
dvander@145
    98
						*ptr = '\0';
dvander@145
    99
						break;
dvander@145
   100
					}
dvander@145
   101
				}
dvander@145
   102
			} else {
dvander@145
   103
				if (*ptr == '"')
dvander@145
   104
				{
dvander@145
   105
					in_quote = false;
dvander@145
   106
				}
dvander@145
   107
			}
dvander@145
   108
		}
dvander@145
   109
dvander@145
   110
		if (!len)
dvander@145
   111
		{
dvander@145
   112
			continue;
dvander@145
   113
		}
dvander@145
   114
dvander@145
   115
		ptr = save_ptr;
dvander@145
   116
dvander@145
   117
		/* Lastly, strip ending whitespace off */
dvander@145
   118
		for (size_t i=len-1; i>=0 && i<len; i--)
dvander@145
   119
		{
dvander@145
   120
			if (isspace(ptr[i]))
dvander@145
   121
			{
dvander@145
   122
				ptr[i] = '\0';
dvander@145
   123
				len--;
dvander@145
   124
			} else {
dvander@145
   125
				break;
dvander@145
   126
			}
dvander@145
   127
		}
dvander@145
   128
dvander@145
   129
		if (!len)
dvander@145
   130
		{
dvander@145
   131
			continue;
dvander@145
   132
		}
dvander@145
   133
dvander@145
   134
		if (!ini_listener->ReadINI_RawLine(ptr, &curtok))
dvander@145
   135
		{
dvander@145
   136
			goto event_failed;
dvander@145
   137
		}
dvander@145
   138
dvander@145
   139
		if (*ptr == '[')
dvander@145
   140
		{
dvander@145
   141
			bool invalid_tokens = false;
dvander@145
   142
			bool got_bracket = false;
dvander@145
   143
			bool extra_tokens = false;
dvander@145
   144
			char c;
dvander@145
   145
dvander@145
   146
			for (size_t i=1; i<len; i++)
dvander@145
   147
			{
dvander@145
   148
				c = ptr[i];
dvander@145
   149
				if (!isalnum(c) && !g_ini_chartable1[c])
dvander@145
   150
				{
dvander@145
   151
					/* First check - is this a bracket? */
dvander@145
   152
					if (c == ']')
dvander@145
   153
					{
dvander@145
   154
						/* Yes! */
dvander@145
   155
						got_bracket = true;
dvander@145
   156
						/* If this isn't the last character... */
dvander@145
   157
						if (i != len - 1)
dvander@145
   158
						{
dvander@145
   159
							extra_tokens = true;
dvander@145
   160
						}
dvander@145
   161
						/* terminate */
dvander@145
   162
						ptr[i] = '\0';
dvander@145
   163
						break;
dvander@145
   164
					} else {
dvander@145
   165
						/* n...No! Continue copying. */
dvander@145
   166
						invalid_tokens = true;
dvander@145
   167
					}
dvander@145
   168
				}
dvander@145
   169
			}
dvander@145
   170
dvander@145
   171
			/* Tell the handler */
dvander@145
   172
			if (!ini_listener->ReadINI_NewSection(&ptr[1], invalid_tokens, got_bracket, extra_tokens, &curtok))
dvander@145
   173
			{
dvander@145
   174
				goto event_failed;
dvander@145
   175
			}
dvander@145
   176
		} else {
dvander@145
   177
			char *key_ptr = ptr;
dvander@145
   178
			char *val_ptr = NULL;
dvander@145
   179
			char c;
dvander@145
   180
			size_t first_space = 0;
dvander@145
   181
			bool invalid_tokens = false;
dvander@145
   182
			bool equal_token = false;
dvander@145
   183
			bool quotes = false;
dvander@145
   184
			
dvander@145
   185
			for (size_t i=0; i<len; i++)
dvander@145
   186
			{
dvander@145
   187
				c = ptr[i];
dvander@145
   188
				/* is this an invalid char? */
dvander@145
   189
				if (!isalnum(c) && !g_ini_chartable1[c])
dvander@145
   190
				{
dvander@145
   191
					if (isspace(c))
dvander@145
   192
					{
dvander@145
   193
						/* if it's a space, keep track of the last space */
dvander@145
   194
						if (!first_space)
dvander@145
   195
						{
dvander@145
   196
							first_space = i;
dvander@145
   197
						}
dvander@145
   198
					} else {
dvander@145
   199
						if (c == '=')
dvander@145
   200
						{
dvander@145
   201
							/* if it's an equal sign, we're done with the key */
dvander@145
   202
							if (first_space)
dvander@145
   203
							{
dvander@145
   204
								/* remove excess whitespace */
dvander@145
   205
								key_ptr[first_space] = '\0';
dvander@145
   206
							} else {
dvander@145
   207
								/* remove the equal sign */
dvander@145
   208
								key_ptr[i] = '\0';
dvander@145
   209
							}
dvander@145
   210
							if (ptr[++i] != '\0')
dvander@145
   211
							{
dvander@145
   212
								/* If this isn't the end, set next pointer */
dvander@145
   213
								val_ptr = &ptr[i];
dvander@145
   214
							}
dvander@145
   215
							equal_token = true;
dvander@145
   216
							break;
dvander@145
   217
						} else {
dvander@145
   218
							/* Mark that we got something invalid! */
dvander@145
   219
							invalid_tokens = true;
dvander@145
   220
							first_space = 0;
dvander@145
   221
						}
dvander@145
   222
					}
dvander@145
   223
				}
dvander@145
   224
			}
dvander@145
   225
dvander@145
   226
			/* Now we need to parse the value, if any */
dvander@145
   227
			if (val_ptr)
dvander@145
   228
			{
dvander@145
   229
				/* eat up spaces! there shouldn't be any h*/
dvander@145
   230
				while ((*val_ptr != '\0') && isspace(*val_ptr))
dvander@145
   231
				{
dvander@145
   232
					val_ptr++;
dvander@145
   233
				}
dvander@145
   234
				if (*val_ptr == '\0')
dvander@145
   235
				{
dvander@145
   236
					val_ptr = NULL;
dvander@145
   237
					goto skip_value;
dvander@145
   238
				}
dvander@145
   239
				/* Do we have an initial quote? If so, the parsing rules change! */
dvander@145
   240
				if (*val_ptr == '"' && *val_ptr != '\0')
dvander@145
   241
				{
dvander@145
   242
					len = strlen(val_ptr);
dvander@145
   243
					if (val_ptr[len-1] == '"')
dvander@145
   244
					{
dvander@145
   245
						/* Strip quotes! */
dvander@145
   246
						val_ptr[--len] = '\0';
dvander@145
   247
						val_ptr++;
dvander@145
   248
						quotes = true;
dvander@145
   249
					}
dvander@145
   250
				}
dvander@145
   251
			}
dvander@145
   252
skip_value:
dvander@145
   253
			/* We're done! */
dvander@145
   254
			curtok = val_ptr - buffer;
dvander@145
   255
			if (!ini_listener->ReadINI_KeyValue(key_ptr, val_ptr, invalid_tokens, equal_token, quotes, &curtok))
dvander@145
   256
			{
dvander@145
   257
				curtok = 0;
dvander@145
   258
				goto event_failed;
dvander@145
   259
			}
dvander@145
   260
		}
dvander@145
   261
	}
dvander@145
   262
dvander@145
   263
	if (line)
dvander@145
   264
	{
dvander@145
   265
		*line = curline;
dvander@145
   266
	}
dvander@145
   267
dvander@145
   268
	fclose(fp);
dvander@145
   269
dvander@145
   270
	return true;
dvander@145
   271
dvander@145
   272
event_failed:
dvander@145
   273
	if (line)
dvander@145
   274
	{
dvander@145
   275
		*line = curline;
dvander@145
   276
	}
dvander@145
   277
dvander@145
   278
	if (col)
dvander@145
   279
	{
dvander@145
   280
		*col = curtok;
dvander@145
   281
	}
dvander@145
   282
dvander@145
   283
	fclose(fp);
dvander@145
   284
dvander@145
   285
	return false;
dvander@145
   286
}