renamed mm_api, I don't like short names!

finished and tested the INI parser and its API

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40150
This commit is contained in:
David Anderson 2006-11-06 10:57:37 +00:00
parent 13775b11b6
commit f19fbac013
7 changed files with 382 additions and 11 deletions

286
core/CTextParsers.cpp Normal file
View File

@ -0,0 +1,286 @@
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "CTextParsers.h"
CTextParsers g_TextParse;
static int g_ini_chartable1[255] = {0};
CTextParsers::CTextParsers()
{
g_ini_chartable1['_'] = 1;
g_ini_chartable1['-'] = 1;
g_ini_chartable1[','] = 1;
g_ini_chartable1['+'] = 1;
g_ini_chartable1['.'] = 1;
g_ini_chartable1['$'] = 1;
g_ini_chartable1['?'] = 1;
g_ini_chartable1['/'] = 1;
}
bool CTextParsers::ParseFile_SMC(const char *file, ITextListener_SMC *smc_listener, unsigned int *line, unsigned int *col)
{
/* :TODO: Implement this */
if (line)
{
*line = 0;
}
return false;
}
bool CTextParsers::ParseFile_INI(const char *file, ITextListener_INI *ini_listener, unsigned int *line, unsigned int *col)
{
FILE *fp = fopen(file, "rt");
unsigned int curline = 0;
unsigned int curtok;
size_t len;
if (!fp)
{
if (line)
{
*line = 0;
}
return false;
}
char buffer[2048];
char *ptr, *save_ptr;
bool in_quote;
while (!feof(fp))
{
curline++;
curtok = 0;
buffer[0] = '\0';
if (fgets(buffer, sizeof(buffer), fp) == NULL)
{
break;
}
/* Preprocess the string before anything */
ptr = buffer;
/* First strip beginning whitespace */
while ((*ptr != '\0') && isspace(*ptr))
{
ptr++;
}
len = strlen(ptr);
if (!len)
{
continue;
}
/* Now search for comment characters */
in_quote = false;
save_ptr = ptr;
for (size_t i=0; i<len; i++,ptr++)
{
if (!in_quote)
{
switch (*ptr)
{
case '"':
{
in_quote = true;
break;
}
case ';':
{
/* Stop the loop */
len = i;
/* Terminate the string here */
*ptr = '\0';
break;
}
}
} else {
if (*ptr == '"')
{
in_quote = false;
}
}
}
if (!len)
{
continue;
}
ptr = save_ptr;
/* Lastly, strip ending whitespace off */
for (size_t i=len-1; i>=0 && i<len; i--)
{
if (isspace(ptr[i]))
{
ptr[i] = '\0';
len--;
} else {
break;
}
}
if (!len)
{
continue;
}
if (!ini_listener->ReadINI_RawLine(ptr, &curtok))
{
goto event_failed;
}
if (*ptr == '[')
{
bool invalid_tokens = false;
bool got_bracket = false;
bool extra_tokens = false;
char c;
for (size_t i=1; i<len; i++)
{
c = ptr[i];
if (!isalnum(c) && !g_ini_chartable1[c])
{
/* First check - is this a bracket? */
if (c == ']')
{
/* Yes! */
got_bracket = true;
/* If this isn't the last character... */
if (i != len - 1)
{
extra_tokens = true;
}
/* terminate */
ptr[i] = '\0';
break;
} else {
/* n...No! Continue copying. */
invalid_tokens = true;
}
}
}
/* Tell the handler */
if (!ini_listener->ReadINI_NewSection(&ptr[1], invalid_tokens, got_bracket, extra_tokens, &curtok))
{
goto event_failed;
}
} else {
char *key_ptr = ptr;
char *val_ptr = NULL;
char c;
size_t first_space = 0;
bool invalid_tokens = false;
bool equal_token = false;
bool quotes = false;
for (size_t i=0; i<len; i++)
{
c = ptr[i];
/* is this an invalid char? */
if (!isalnum(c) && !g_ini_chartable1[c])
{
if (isspace(c))
{
/* if it's a space, keep track of the last space */
if (!first_space)
{
first_space = i;
}
} else {
if (c == '=')
{
/* if it's an equal sign, we're done with the key */
if (first_space)
{
/* remove excess whitespace */
key_ptr[first_space] = '\0';
} else {
/* remove the equal sign */
key_ptr[i] = '\0';
}
if (ptr[++i] != '\0')
{
/* If this isn't the end, set next pointer */
val_ptr = &ptr[i];
}
equal_token = true;
break;
} else {
/* Mark that we got something invalid! */
invalid_tokens = true;
first_space = 0;
}
}
}
}
/* Now we need to parse the value, if any */
if (val_ptr)
{
/* eat up spaces! there shouldn't be any h*/
while ((*val_ptr != '\0') && isspace(*val_ptr))
{
val_ptr++;
}
if (*val_ptr == '\0')
{
val_ptr = NULL;
goto skip_value;
}
/* Do we have an initial quote? If so, the parsing rules change! */
if (*val_ptr == '"' && *val_ptr != '\0')
{
len = strlen(val_ptr);
if (val_ptr[len-1] == '"')
{
/* Strip quotes! */
val_ptr[--len] = '\0';
val_ptr++;
quotes = true;
}
}
}
skip_value:
/* We're done! */
curtok = val_ptr - buffer;
if (!ini_listener->ReadINI_KeyValue(key_ptr, val_ptr, invalid_tokens, equal_token, quotes, &curtok))
{
curtok = 0;
goto event_failed;
}
}
}
if (line)
{
*line = curline;
}
fclose(fp);
return true;
event_failed:
if (line)
{
*line = curline;
}
if (col)
{
*col = curtok;
}
fclose(fp);
return false;
}

27
core/CTextParsers.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef _INCLUDE_SOURCEMOD_TEXTPARSERS_H_
#define _INCLUDE_SOURCEMOD_TEXTPARSERS_H_
#include "interfaces/ITextParsers.h"
using namespace SourceMod;
class CTextParsers : public ITextParsers
{
public:
CTextParsers();
public:
virtual bool ParseFile_INI(const char *file,
ITextListener_INI *ini_listener,
unsigned int *line,
unsigned int *col);
virtual bool ParseFile_SMC(const char *file,
ITextListener_SMC *smc_listener,
unsigned int *line,
unsigned int *col);
};
extern CTextParsers g_TextParse;
#endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_H_

View File

@ -1,5 +1,5 @@
#ifndef _INCLUDE_SOURCEMOD_TEXTPARSERS_H_
#define _INCLUDE_SOURCEMOD_TEXTPARSERS_H_
#ifndef _INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_
#define _INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_
#include <IShareSys.h>
@ -50,9 +50,18 @@ namespace SourceMod
* @brief Called when a new section is encountered in an INI file.
*
* @param section Name of section in between the [ and ] characters.
* @param invalid_tokens True if invalid tokens were detected in the name.
* @param close_bracket True if a closing bracket was detected, false otherwise.
* @param extra_tokens True if extra tokens were detected on the line.
* @param curtok Contains current token in the line where the section name starts.
* You can add to this offset when failing to point to a token.
* @return True to keep parsing, false otherwise.
*/
virtual bool ReadINI_NewSection(const char *section)
virtual bool ReadINI_NewSection(const char *section,
bool invalid_tokens,
bool close_bracket,
bool extra_tokens,
unsigned int *curtok)
{
return true;
}
@ -61,11 +70,32 @@ namespace SourceMod
* @brief Called when encountering a key/value pair in an INI file.
*
* @param key Name of key.
* @param value Name of value.
* @param value String containing value (with quotes stripped, if any).
* @param invalid_tokens Whether or not the key contained invalid tokens.
* @param equal_token There was an '=' sign present (in case the value is missing).
* @param quotes Whether value was enclosed in quotes.
* @param curtoken Contains the token index of the start of the value string.
* This can be changed when returning false.
* @return True to keep parsing, false otherwise.
*/
virtual bool ReadINI_KeyValue(const char *key, const char *value, bool quotes)
virtual bool ReadINI_KeyValue(const char *key,
const char *value,
bool invalid_tokens,
bool equal_token,
bool quotes,
unsigned int *curtok)
{
return true;
}
/**
* @brief Called after a line has been preprocessed, if it has text.
*
* @param line Contents of line.
* @param curtok Pointer to optionally store failed position in string.
* @return True to keep parsing, false otherwise.
*/
virtual bool ReadINI_RawLine(const char *line, unsigned int *cutok)
{
return true;
}
@ -163,8 +193,20 @@ namespace SourceMod
}
};
#define SMINTERFACE_TEXTPARSERS_NAME "ITextParsers"
#define SMINTERFACE_TEXTPARSERS_VERSION 1
class ITextParsers : public SMInterface
{
public:
virtual const char *GetInterfaceName()
{
return SMINTERFACE_TEXTPARSERS_NAME;
}
virtual unsigned int GetInterfaceVersion()
{
return SMINTERFACE_TEXTPARSERS_VERSION;
}
public:
/**
* @brief Parses an INI-format file.
@ -199,4 +241,4 @@ namespace SourceMod
};
};
#endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_H_
#endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_

View File

@ -179,7 +179,11 @@
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\mm_api.cpp"
RelativePath="..\CTextParsers.cpp"
>
</File>
<File
RelativePath="..\sourcemm_api.cpp"
>
</File>
</Filter>
@ -189,7 +193,7 @@
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\mm_api.h"
RelativePath="..\CTextParsers.h"
>
</File>
<File
@ -200,6 +204,10 @@
RelativePath="..\sm_version.h"
>
</File>
<File
RelativePath="..\sourcemm_api.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"

View File

@ -1,16 +1,24 @@
#include <oslink.h>
#include "mm_api.h"
#include "sourcemm_api.h"
#include "sm_version.h"
#include "systems/LibrarySys.h"
#include "CTextParsers.h"
SourceMod_Core g_SourceMod;
PLUGIN_EXPOSE(SourceMod, g_SourceMod);
class Test : public ITextListener_INI
{
public:
};
bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late)
{
PLUGIN_SAVEVARS();
Test test;
bool result = g_TextParse.ParseFile_INI("c:\\gaben.ini", &test, NULL, NULL);
return true;
}

View File

@ -48,7 +48,7 @@ private:
LibraryHandle m_lib;
};
class LibrarySystem
class LibrarySystem : public ILibrarySys
{
public:
virtual ILibrary *OpenLibrary(const char *path, char *error, size_t err_max);