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