Nico Yazawa
Бывший MrChester =(
- Сообщения
- 326
- Реакции
- 303
[SourcePawn] Статья - Работа с SMC Parser
Писал статью в стиле уроков от @R1KO, чтобы было удобно и приятно ее читать.
Оригинальная статья
textparse.inc
textparse · SourceMod Scripting API Reference
SMC Parser - универсальный инструмент (парсер), основанный на каллбеках, позволяющий читать файлы конфигурации SourceMod.
SMC Parser проходит по всему конфигу сверху вниз, читая все секции и ключи в них. Каждая новая секция или ключ это отдельный вызов каллбека.
Чем SMC Parser отличается от KeyValues?
1) SMC Parser не может обрабатывать отдельные записи (то есть ключ без значения).
2) SMC Parser поддерживает многострочные комментарии (/* комментарий /*), когда KeyValues - нет.
3) SMC Parser прочитает все категории и ключи по порядку, когда в KeyValues нельзя узнать значение двух ключей с одинаковым названием.
4) SMC Parser не поддерживает изменения самого конфиг файла, когда в KeyValues это реализуемо.
Методы и свойства для для работы с SMC Parser можно найти здесь: SMCParser · textparse · SourceMod Scripting API Reference
Давайте рассмотрим их подробнее:
- Методы SMC Parser:
- SMCParser - Создает объект типа SMC Parser.
C-подобный:SMCParser hParser = new SMCParser(); // Создание нового объекта SMCParser
- GetErrorString - Получает строку ошибки SMCError.
C-подобный:char error[128]; // Создаем строку для хранения ошибки SMC_GetErrorString(result, error, sizeof(error)); // Записываем ошибку в нашу строку
- ParseFile - Запускает инструмент (парсер).
C-подобный:SMCError ParseFile(const char[] file, int& line, int& col)
- const char[] file - Путь к конфиг файлу
- int& line - Номер строки, на которой находится парсер
- int& col - Номер столбца, на котором находится парсер
-
C-подобный:
char file[128]; // Условно, наш конфиг файл, который мы будем парсить int line = 0; // Буффер, в котором будет храниться строка, на которой находится парсер int col = 0; // Буффер, в котором будет храниться столбец, на котором находится парсер hParser.ParseFile(file, line, col); // Запускаем наш парсер
- SMCParser - Создает объект типа SMC Parser.
- Свойства SMC Parser:
- OnStart - Устанавливает каллбек, который вызывается в начале работы парсера.
C-подобный:// Такое в коде писать не надо, тут показано присваивание каллбека к парсеру и как должен выглядеть каллбек. hParser.OnStart = SMC_ParseStart; typedef SMC_ParseStart = function void(SMCParser smc);
- OnEnd - Устанавливает каллбек, который вызывается в конце работы парсера.
C-подобный:// Такое в коде писать не надо, тут показано присваивание каллбека к парсеру и как должен выглядеть каллбек. hParser.OnEnd = SMC_ParseEnd; typedef SMC_ParseEnd = function void(SMCParser smc, bool halted, bool failed);
- OnEnterSection - Устанавливает каллбек, который вызывается, как только парсер открыл новую секцию.
C-подобный:// Такое в коде писать не надо, тут показано присваивание каллбека к парсеру и как должен выглядеть каллбек. hParser.OnEnterSection = SMC_NewSection; typedef SMC_NewSection = function SMCResult(SMCParser smc, const char[] name, bool opt_quotes);
- OnLeaveSection - Устанавливает каллбек, который вызывается, как только парсер покинул текущую секцию.
C-подобный:// Такое в коде писать не надо, тут показано присваивание каллбека к парсеру и как должен выглядеть каллбек. hParser.OnLeaveSection = SMC_EndSection; typedef SMC_EndSection = function SMCResult(SMCParser smc);
- OnKeyValue - Устанавливает каллбек, который вызывается, когда парсер нашел новый ключ и значение к нему.
C-подобный:// Такое в коде писать не надо, тут показано присваивание каллбека к парсеру и как должен выглядеть каллбек. hParser.OnKeyValue = SMC_KeyValue; typedef SMC_KeyValue = function SMCResult(SMCParser smc, const char[] key, const char[] value, bool key_quotes, bool value_quotes);
- OnRawLine - Устанавливает каллбек, который вызывается, когда парсер обнаружил новую строку? Никогда этим не пользовался .-.
C-подобный:// Такое в коде писать не надо, тут показано присваивание каллбека к парсеру и как должен выглядеть каллбек. hParser.OnRawLine = SMC_KeyValue; typedef SMC_RawLine = function SMCResult(SMCParser smc, const char[] line, int lineno);
- OnStart - Устанавливает каллбек, который вызывается в начале работы парсера.
А теперь давайте рассмотрим работу SMC Parser в коде:
Рекомендую всегда создавать отдельную функцию для таких затей:
C-подобный:
ProcessConfigFile("configs/someconfigfile.cfg");
А вот и сама функция:
C-подобный:
public void ProcessConfigFile(const char[] file)
{
char ConfigFile[PLATFORM_MAX_PATH]; // Создаем нашу строку, где будет храниться реальный путь к файлу
BuildPath(Path_SM, ConfigFile, sizeof(ConfigFile), file); // Записываем наш путь в строку
if (!FileExists(ConfigFile)) // Проверяем, что файл валиден и существует
{
// Файл не существует, останавливаем плагин и пишем об ошибке!
LogError("[SM] Plugin is not running! Could not find file %s", ConfigFile);
SetFailState("Could not find file %s", ConfigFile);
}
// Наша новая функция будет возвращать bool
else if (!ParseConfigFile(ConfigFile)) // Проверяем, что все прошло без ошибок
{
// У нас какая-то ошибка, останавливаем плагин и пишем об ошибке!
LogError("[SM] Plugin is not running! Failed to parse %s", ConfigFile);
SetFailState("Parse error on file %s", ConfigFile);
}
}
Вы могли заметить новую функцию
ParseConfigFile(sConfigFile)
, ее сейчас и напишем:
C-подобный:
public bool ParseConfigFile(const char[] file)
{
SMCParser hParser = new SMCParser(); // Создаем SMCParser
char error[128]; // Создаем строку для хранения ошибки
int line = 0, col = 0; // Создаем буффера для хранения строки и колонки
// Устанавливаем все необходимые каллбеки
hParser.OnEnterSection = Config_NewSection;
hParser.OnLeaveSection = Config_EndSection;
hParser.OnKeyValue = Config_KeyValue;
hParser.OnEnd = Config_End;
// Запускаем SMCParser, получаем его результат и закрываем
SMCError result = SMC_ParseFile(hParser, file, line, col);
CloseHandle(hParser);
// Убеждаемся, что все без ошибок прошло
if (result != SMCError_Okay)
{
// В случае ошибки просто пишем об этом в еррор лог
SMC_GetErrorString(result, error, sizeof(error));
LogError("%s on line %d, col %d of %s", error, line, col, file);
}
// Ну и возвращаем true/false в зависимости от успешности парсера
return (result == SMCError_Okay);
}
Ну и остались наши дорогие каллбеки:
C-подобный:
public SMCResult Config_NewSection(Handle parser, const char[] section, bool quotes) // Каллбек новой секции
{
// Давайте убедимся, что наша секция не является самой главной (как это есть в KV)
if (StrEqual(section, "top_sectioname"))
{
return SMCParse_Continue;
}
// Тут можно дальше продолжать проверки...
// У нас есть название секции (section) и наличие кавычек (quotes)
return SMCParse_Continue;
}
public SMCResult Config_KeyValue(Handle parser, char[] key, char[] value, bool key_quotes, bool value_quotes) // Каллбек нового ключа
{
// В данном каллбеке у нас есть сам ключ (key) и значение к нему (value)
// А также наличие кавычек в обоих случаях
if(StrEqual(key, "somekey", false))
{
// Можно тут что-нибудь сделать
PushArrayString(hSomeArray, value);
}
else if(StrEqual(key, "someotherkey", false))
{
// Или тут
}
return SMCParse_Continue;
}
public SMCResult Config_EndSection(Handle parser) // Калбек конца секции
{
return SMCParse_Continue;
}
public Config_End(Handle parser, bool halted, bool failed) // Калбек окончания парсера
{
// Проверяем все ли хорошо
if (failed)
{
// В случае неудачи останавливаем работу плагина
SetFailState("Plugin configuration error");
}
}
Я надеюсь, что это статья была полезна для вас)
С радостью прочитаю всю конструктивную критику, может дополнить статью вашими силами)
Последнее редактирование: