/* ! file encoding: Windows-1251 ------------------------------------------ Самый быстрый INI-ридер/райтер ( mxINI ) ------------------ ЧТО ЭТО - Это инклуд-файл для PAWN-скриптов мультиплеера GTA San Andreas (SA-MP) КАК ИСПОЛЬЗОВАТЬ - Поместить этот файл в папку include, которая лежит рядом с компилятором - В самом верху вашего скрипта добавить #include АВТОР MX_Master ВЕРСИЯ 0.5.3 от 01.10.2018 (основано на 0.5 от 20.09.2010) ДОСТУПНЫЕ ИНСТРУМЕНТЫ более подробные описания даны перед каждой функцией ниже в коде ini_createFile ( "путь/к/файлу.ini", "Содержимое файла по умолчанию" ) ini_openFile ( "путь/к/файлу.ini" ) ini_closeFile ( ИД_открытого_файла ) -- ini_setString ( ИД_открытого_файла, "имя ключа", "текстовое значение" ) ini_setInteger ( ИД_открытого_файла, "имя ключа", 123456 ) ini_setFloat ( ИД_открытого_файла, "имя ключа", 3.1416 ) -- ini_getString ( ИД_открытого_файла, "имя ключа", returnValue ) ini_getInteger ( ИД_открытого_файла, "имя ключа", returnValue ) ini_getFloat ( ИД_открытого_файла, "имя ключа", returnValue ) -- ini_removeKey ( ИД_открытого_файла, "имя ключа" ) ini_getErrorInfo ( Код_ошибки ) ПРИМЕРЫ new iniFile = ini_createFile ( "test4268.ini" ); if ( iniFile < 0 ) iniFile = ini_openFile ( "test4268.ini" ); if ( iniFile >= 0 ) { new returnString[32], returnNumber, Float: returnFloat; ini_setString ( iniFile, "ключ со строкой", "текстовое значение" ); ini_setInteger ( iniFile, "ключ с числом", 123456 ); ini_setFloat ( iniFile, "ключ с дробью", 3.1416 ); ini_removeKey ( iniFile, "ключ с числом" ); ini_getString ( iniFile, "ключ со строкой", returnString ); ini_getInteger ( iniFile, "ключ с числом", returnNumber ); ini_getFloat ( iniFile, "ключ с дробью", returnFloat ); ini_closeFile ( iniFile ); printf ( "\n `ключ_со_строкой` = `%s`,\n `ключ_с_числом` = `%d`,\n `ключ_с_дробью` = `%f` \n", returnString, returnNumber, returnFloat ); } else print( "\n Не удалось открыть INI файл \n" ); */ #if defined _mxINI_included #endinput #endif #define _mxINI_included const // настройки // РЕКОМЕНДУЕТСЯ ИЗМЕНИТЬ ПОД СЕБЯ #if !defined INI_MAX_OPENED_FILES INI_MAX_OPENED_FILES = 2, // максимум открытых одновременно файлов #endif #if !defined INI_MAX_FILE_SIZE INI_MAX_FILE_SIZE = 65536, // байт, макс. размер файла #endif #if !defined INI_MAX_FILENAME_SIZE INI_MAX_FILENAME_SIZE = 128, // символов, макс. размер пути к файлу #endif #if !defined INI_MAX_KEYS_IN_FILE INI_MAX_KEYS_IN_FILE = 2048, // максимум ключей в открытом файле #endif // в ОЗУ будет выделено для временного хранения файлов примерно вот столько байт: // INI_MAX_OPENED_FILES * ( INI_MAX_FILE_SIZE + INI_MAX_FILENAME_SIZE*4 + INI_MAX_KEYS_IN_FILE*4 ) // НЕЛЬЗЯ МЕНЯТЬ INI_INTEGER_SIZE = 12, // размер строки с целочисленным значением INI_FLOAT_SIZE = 40, // размер строки с дробным числовым значением INI_STRING_DELIMITER = '\n', // разделитель строк INI_DELIMITER = '=', // разделитель ключа и значения // коды ошибок, возвращаемые функциями // РЕКОМЕНДУЕТСЯ НЕ ИЗМЕНЯТЬ INI_OK = 0, // функция успешно выполнена // проверять на ошибку можно так: // if ( возвращаемое_значение_функции < 0 ) ... INI_FILE_NOT_FOUND = -1, // файл не найден по указанному пути INI_FILE_ALREADY_EXIST = -2, // файл не найден по указанному пути INI_TOO_LARGE_FILE = -3, // размер файла превысил допустимый лимит INI_WRONG_PATH_SIZE = -4, // неправильный размер пути к файлу INI_READ_ERROR = -5, // ошибка чтения файла INI_WRITE_ERROR = -6, // ошибка при записи в файл INI_NO_FREE_SLOT = -7, // нет свободного слота для открытия файла INI_WRONG_SLOT = -8, // указан неверный слот открытого файла INI_KEY_NOT_FOUND = -9, // ключ в открытом файле не найден INI_WRONG_RETURN_SIZE = -10, // размер строки, в которую будет помещено значение ключа - указан неверно (<= 0) // другие вспомогательные константы // НЕЛЬЗЯ МЕНЯТЬ cellbytes = cellbits / charbits; // кол-во байт в одной ячейке // списки разных символов для оператора case в одной из функций // РЕКОМЕНДУЕТСЯ НЕ ИЗМЕНЯТЬ #define INI_SPACE_CHARS ' ', '\t' // строковые пробельные символы #define INI_KEY_STARTS ' ', '\t', '\r', '\n', '\0' // символы, перед началом ключа #define INI_STRING_ENDS '\r', '\n', '\0' // символы, завершающие значение #define INI_NUMBER_ENDS ' ', '\t', '\r', '\n', '\0' // символы, завершающие численное значение static stock // временное хранилище открытых файлов _ini_nSlotUsed [ INI_MAX_OPENED_FILES ], // флаг: занят ли слот _ini_nFileChanged [ INI_MAX_OPENED_FILES ], // флаг: был ли изменен файл _ini_nFileBusy [ INI_MAX_OPENED_FILES ], // флаг: изменяется ли в данный момент содержимое файла _ini_nFileSize [ INI_MAX_OPENED_FILES ], // размер открытого файла _ini_nDelimPos [ INI_MAX_OPENED_FILES ] [ INI_MAX_KEYS_IN_FILE ], // список позиций INI_DELIMITER _ini_nKeysCount [ INI_MAX_OPENED_FILES ], // кол-во ключей открытого файла _ini_szFilePath [ INI_MAX_OPENED_FILES ] [ INI_MAX_FILENAME_SIZE ], // путь к файлу _ini_szFileContent [ INI_MAX_OPENED_FILES ] [ INI_MAX_FILE_SIZE char ]; // контент файла /* Создает и сразу открывает INI файл для чтения/записи. ПОДРОБНЕЕ Файл создается только в ОЗУ, и в него записывается строка szDefaultContent. В szDefaultContent могут быть и ключи, которые потом парсер также будет видеть. Только при закрытии файла, его содержимое будет записано на диск по указанному пути к файлу. ПАРАМЕТРЫ: szFilePath[] путь к файлу szDefaultContent контент файла по умолчанию, обычно, можно не указывать ВЕРНЕТ: код ошибки < 0 или ИД_открытого_файла */ stock ini_createFile ( const szFilePath[], const szDefaultContent[] = "" ) { // // несколько блоков с проверками // // ------------ new nFileNameSize = strlen( szFilePath ); // узнаем размер пути // если размер пути неправильный if ( nFileNameSize <= 0 || nFileNameSize >= INI_MAX_FILENAME_SIZE ) return INI_WRONG_PATH_SIZE; // вернем код ошибки // ------------ // ------------ if ( fexist( szFilePath ) ) // если файл уже существует return INI_FILE_ALREADY_EXIST; // вернем код ошибки - файл уже существует for ( new slot = 0; slot < INI_MAX_OPENED_FILES; slot++ ) // перебор всех слотов ОЗУ if // если уже есть такой открытый файл ( _ini_nSlotUsed[slot] != 0 && strcmp( szFilePath, _ini_szFilePath[slot], false ) == 0 ) return INI_FILE_ALREADY_EXIST; // вернем код ошибки - файл уже существует // ------------ // ------------ new nFileSize = strlen( szDefaultContent ); // узнаем размер контентa файла по умолчанию // если размер неправильный if ( nFileSize < 0 || nFileSize >= INI_MAX_FILE_SIZE ) return INI_TOO_LARGE_FILE; // вернем код ошибки // ------------ // // поиск свободного слота для записи в ОЗУ // for ( new slot = 0; slot < INI_MAX_OPENED_FILES; slot++ ) // перебор всех слотов ОЗУ { if ( _ini_nSlotUsed[slot] != 1 ) // если слот найден { // ------------ _ini_nSlotUsed[slot] = 1; // застолбим найденное место _ini_nFileChanged[slot] = 0; // файл не был изменен _ini_nFileSize[slot] = nFileSize; // скопируем размер файла в слот _ini_nKeysCount[slot] = 0; // кол-во ключей выставим 0 // ------------ // ------------ // скопируем в ОЗУ весь файл, // запомнив все позиции INI_DELIMITER и их кол-во for ( new i = 0; i < nFileSize && i < INI_MAX_FILE_SIZE; i++ ) { if ( szDefaultContent[i] == INI_DELIMITER // если символ это INI_DELIMITER && _ini_nKeysCount[slot] < INI_MAX_KEYS_IN_FILE // и лимит ключей еще не исчерпан ) { _ini_nDelimPos[slot][ _ini_nKeysCount[slot] ] = i; // добавим еще одну позицию INI_DELIMITER _ini_nKeysCount[slot]++; // увеличим кол-во найденных ключей } _ini_szFileContent[slot]{i} = szDefaultContent[i]; } _ini_szFileContent[slot]{nFileSize} = 0; // символ конца строки для контента // ------------ // ------------ // скопируем в озу путь к файлу memcpy( _ini_szFilePath[slot], szFilePath, 0, nFileNameSize * cellbytes ); _ini_szFilePath[slot][nFileNameSize] = 0; // символ конца строки для пути // ------------ return slot; // вернем ИД слота } } // // если свободный слот в памяти не найден // return INI_NO_FREE_SLOT; // вернем код ошибки // ------------ } /* Открывает INI файл для чтения/записи, если он существует. ПОДРОБНЕЕ Копирует в ОЗУ с диска всё содержимое файла, если его размер не превышает допустимый. Если кол-во ключей в файле больше допустимого, ошибки никакой не будет, просто при чтении/записи значений, парсер не будет видеть лишние ключи. ПАРАМЕТРЫ: szFilePath[] путь к файлу ВЕРНЕТ: код ошибки < 0 или ИД_открытого_файла */ stock ini_openFile ( const szFilePath[] ) { // // несколько блоков с проверками // // ------------ new nFileNameSize = strlen( szFilePath ); // узнаем размер пути // если размер пути неправильный if ( nFileNameSize <= 0 || nFileNameSize >= INI_MAX_FILENAME_SIZE ) return INI_WRONG_PATH_SIZE; // вернем код ошибки // ------------ if ( ! fexist( szFilePath ) ) // если файл не найден return INI_FILE_NOT_FOUND; // вернем код ошибки // ------------ // проверка - открыт ли уже файл с таким именем for ( new slot = 0; slot < INI_MAX_OPENED_FILES; slot++ ) // перебор всех слотов ОЗУ if // если уже есть такой открытый файл ( _ini_nSlotUsed[slot] != 0 && strcmp( szFilePath, _ini_szFilePath[slot], false ) == 0 ) return slot; // просто вернем его слот // ------------ // ------------ new File: pFile = fopen( szFilePath, io_read ); // пытаемся открыть файл для чтения if ( ! pFile ) // если файл не открылся return INI_READ_ERROR; // вернем код ошибки // ------------ // ------------ new nFileSize = flength( pFile ); // узнаем размер файла if ( nFileSize >= INI_MAX_FILE_SIZE ) // если размер файла слишком большой { fclose(pFile); // закроем файл return INI_TOO_LARGE_FILE; // вернем код ошибки } // ------------ // // поиск свободного слота для записи в ОЗУ // // ------------ for ( new slot = 0; slot < INI_MAX_OPENED_FILES; slot++ ) // перебор всех слотов ОЗУ { if ( _ini_nSlotUsed[slot] != 1 ) // если слот найден { // ------------ _ini_nSlotUsed[slot] = 1; // застолбим найденное место _ini_nFileChanged[slot] = 0; // файл не был изменен _ini_nFileSize[slot] = nFileSize; // скопируем размер файла в слот _ini_nKeysCount[slot] = 0; // кол-во ключей выставим 0 // ------------ // ------------ // скопируем в ОЗУ весь файл, // запомнив все позиции INI_DELIMITER и их кол-во for ( new i = 0, symbol, nextstr = 1; i < nFileSize && i < INI_MAX_FILE_SIZE; i++ ) { symbol = fgetchar( pFile, 0, false ); // читаем из файла следующий символ if ( symbol == INI_STRING_DELIMITER ) // если начинается новая строка nextstr = 1; if ( nextstr // если обрабатывается следующая строка && symbol == INI_DELIMITER // если символ это INI_DELIMITER && _ini_nKeysCount[slot] < INI_MAX_KEYS_IN_FILE // и лимит ключей еще не исчерпан ) { _ini_nDelimPos[slot][ _ini_nKeysCount[slot] ] = i; // добавим еще одну позицию INI_DELIMITER _ini_nKeysCount[slot]++; // увеличим кол-во найденных ключей nextstr = 0; // сбрасываем информацию о новой строке } _ini_szFileContent[slot]{i} = symbol; } _ini_szFileContent[slot]{nFileSize} = 0; // символ конца строки для контента fclose(pFile); // закроем файл // ------------ // ------------ // скопируем в озу путь к файлу memcpy( _ini_szFilePath[slot], szFilePath, 0, nFileNameSize * cellbytes ); _ini_szFilePath[slot][nFileNameSize] = 0; // символ конца строки для пути // ------------ return slot; // вернем ИД слота } } // ------------ // // если свободный слот в памяти не найден // // ------------ fclose(pFile); // закроем файл return INI_NO_FREE_SLOT; // вернем код ошибки // ------------ } /* Закрывает INI файл, если он был открыт. ПОДРОБНЕЕ Если файл не был изменен - освободит слот для хранения файла в ОЗУ. Если файл был изменен - полностью перезапишет файл на диске. ПАРАМЕТРЫ: nFilePointer ИД_открытого_файла, полученный от ini_openFile / ini_createFile ВЕРНЕТ: код ошибки < 0 или 0 при успехе */ stock ini_closeFile ( nFilePointer ) { if ( // если ИД открытого файла указан верно nFilePointer >= 0 && nFilePointer < INI_MAX_OPENED_FILES && _ini_nSlotUsed[nFilePointer] != 0 ) { if ( _ini_nFileChanged[nFilePointer] != 0 ) // если файл был изменен { new File: pFile = fopen( _ini_szFilePath[nFilePointer], io_write ); // пытаемся открыть файл для записи if ( ! pFile ) // если файл не открылся return INI_WRITE_ERROR; // вернем код ошибки // запишем контент файла из ОЗУ на диск for ( new i = 0; i < _ini_nFileSize[nFilePointer]; i++ ) fputchar( pFile, _ini_szFileContent[nFilePointer]{i}, false ); fclose(pFile); // закроем файл } _ini_nSlotUsed[nFilePointer] = 0; // освободить слот открытого файла return INI_OK; // вернуть код об успешном выполнении функции } return INI_WRONG_SLOT; // вернуть код: неверный указатель на открытый файл } /* Получает из открытого INI файла значение указанного ключа. ПОДРОБНЕЕ Парсер ищет в ОЗУ в контенте файла указанный ключ и помещает в szReturnValue его строковое значение. szReturnValue нужно создать заранее. nSizeOfReturn можно не указывать, если только не нужно точное кол-во возвращаемых символов в строке (в описании этого параметра ниже даны дополнительные указания). Как ключ так и значение в файле, могут быть любой длины и могут содержать любые символы, кроме 2 символов конца строки \r и \n. Парсер не видит пробелы и знаки табуляции вокруг имени ключа и перед значением, он считает их отступами. ПАРАМЕТРЫ: nFilePointer ИД_открытого_файла, полученный от ini_openFile / ini_createFile szKeyName[] имя ключа szReturnValue[] сюда будет помещено значение ключа в виде строки nSizeOfReturn макс. размер возвращаемой строки, обычно, это размер szReturnValue. если ваша строка szReturnValue является частью массива, который был создан с помощью enum, этот параметр нужно обязательно указывать как число ВЕРНЕТ: код ошибки < 0 или 0 при успехе */ stock ini_getString ( nFilePointer, const szKeyName[], szReturnValue[], nSizeOfReturn = sizeof(szReturnValue) ) { // ---------------- if // если ИД открытого файла указан неверно ( nFilePointer < 0 || nFilePointer >= INI_MAX_OPENED_FILES || _ini_nSlotUsed[nFilePointer] != 1 ) return INI_WRONG_SLOT; // вернуть код: неверный указатель на открытый файл // ---------------- if ( nSizeOfReturn <= 0 ) // если по какой-то причине размер возвращаемого значения указан/рассчитан как 0 return INI_WRONG_RETURN_SIZE; // ---------------- new nKeyLen = strlen(szKeyName); // узнаем длину имени указанного ключа if ( nKeyLen <= 0 ) // если указан пустой ключ return INI_KEY_NOT_FOUND; // ---------------- // ---------------- for // перебор и сравнение всех ключей файла с указанным ключом ( new kPos = 0, curFilePos, found = 0; kPos < _ini_nKeysCount[nFilePointer]; kPos++ ) { // ---------------- found = 0; // флаг, найдена ли позиция конца ключа = 0 for // ищем позицию конца ключа ( curFilePos = _ini_nDelimPos[nFilePointer][kPos] - 1; // текущ. поз. файла = поз. текущ. INI_DELIMITER - 1 curFilePos >= 0; // продолжать пока поз. файла >= 0 curFilePos-- // после каждого повтора текущ. поз. файла -= 1 ) { switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) // узнаем что за символ в текущ. поз. файла { case INI_SPACE_CHARS : continue; // если это пробельный символ, перейдем к пред. символу файла case INI_STRING_DELIMITER : break; // если это конец строки default : // если это другой символ { found = 1; // позиция конца ключа найдена break; // конец цикла } } } // если позиция конца ключа не найдена, переход к след. позиции INI_DELIMITER if ( found != 1 ) continue; // ---------------- // сравниваем посимвольно текущий ключ файла и указанный ключ for ( new curKeyPos = nKeyLen - 1; curKeyPos >= 0; curFilePos--, curKeyPos-- ) { if ( curFilePos < 0 // если поз файла стала < 0 || _ini_szFileContent[nFilePointer]{curFilePos} != szKeyName[curKeyPos] // если символы из ключей не равны || _ini_szFileContent[nFilePointer]{curFilePos} == INI_STRING_DELIMITER // если символ из ключа это INI_STRING_DELIMITER ) { found = 0; // флаг, ключ не найден break; // конец сравнения } } // ---------------- if ( found != 0 ) // если указанный ключ найден в файле { // если найдено совпадение не целого ключа файла, а его окончания с указанным ключом if ( curFilePos >= 0 ) { switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_KEY_STARTS : {} default: continue; } } // ---------------- // текущая позиция в файле будет на 1 больше текущей позиции INI_DELIMITER curFilePos = _ini_nDelimPos[nFilePointer][kPos] + 1; // ищем позицию начала значения, она будет помещена в curFilePos for ( ; ; curFilePos++ ) { if ( curFilePos >= _ini_nFileSize[nFilePointer] ) break; switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_SPACE_CHARS : continue; // если это пробельный символ, перейдем к след. символу default : break; // если это другой символ } } // ---------------- // ---------------- // скопируем посимвольно в szReturnValue значение ключа из файла // воспользуемся созданной переменной found как позицией в возвращаемом значении for ( found = 0; found < nSizeOfReturn; found++, curFilePos++ ) { switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_STRING_ENDS : // если это символ конца значения { szReturnValue[found] = 0; // запишем символ конца строки break; // конец копирования } default : // копируем символ из файла в szReturnValue szReturnValue[found] = _ini_szFileContent[nFilePointer]{curFilePos}; } } szReturnValue[nSizeOfReturn - 1] = 0; // на всякий случай обрежем правильно строку return INI_OK; // ---------------- } // ---------------- } // ---------------- // ---------------- return INI_KEY_NOT_FOUND; // ---------------- } /* Получает из открытого INI файла целочисленное значение указанного ключа. ПОДРОБНЕЕ Парсер ищет в ОЗУ в контенте файла указанный ключ и помещает в nReturnValue его целочисленное значение. nReturnValue нужно создать заранее. Имя ключа в файле может быть любой длины, а также может содержать любые символы, кроме 2 символов конца строки \r и \n. Значение может быть только фиксированной длины, которая равна INI_INTEGER_SIZE - 1. Парсер не видит пробелы и знаки табуляции вокруг имени ключа/значения, он считает их отступами. ПАРАМЕТРЫ: nFilePointer ИД_открытого_файла, полученный от ini_openFile / ini_createFile szKeyName[] имя ключа nReturnValue сюда будет помещено значение ключа в виде целого числа ВЕРНЕТ: код ошибки < 0 или 0 при успехе */ stock ini_getInteger ( nFilePointer, const szKeyName[], & nReturnValue ) { // ---------------- if // если ИД открытого файла указан неверно ( nFilePointer < 0 || nFilePointer >= INI_MAX_OPENED_FILES || _ini_nSlotUsed[nFilePointer] != 1 ) return INI_WRONG_SLOT; // вернуть код: неверный указатель на открытый файл // ---------------- // ---------------- new nKeyLen = strlen(szKeyName); // узнаем длину имени указанного ключа if ( nKeyLen <= 0 ) // если указан пустой ключ return INI_KEY_NOT_FOUND; // ---------------- // ---------------- for // перебор и сравнение всех ключей файла с указанным ключом ( new kPos = 0, curFilePos, found = 0; kPos < _ini_nKeysCount[nFilePointer]; kPos++ ) { // ---------------- found = 0; // флаг, найдена ли позиция конца ключа = 0 for // ищем позицию конца ключа ( curFilePos = _ini_nDelimPos[nFilePointer][kPos] - 1; // текущ. поз. файла = поз. текущ. INI_DELIMITER - 1 curFilePos >= 0; // продолжать пока поз. файла >= 0 curFilePos-- // после каждого повтора текущ. поз. файла -= 1 ) { switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) // узнаем что за символ в текущ. поз. файла { case INI_SPACE_CHARS : continue; // если это пробельный символ, перейдем к пред. символу файла case INI_STRING_DELIMITER : break; // если это конец строки default : // если это другой символ { found = 1; // позиция конца ключа найдена break; // конец цикла } } } // если позиция конца ключа не найдена, переход к след. позиции INI_DELIMITER if ( found != 1 ) continue; // ---------------- // сравниваем посимвольно текущий ключ файла и указанный ключ for ( new curKeyPos = nKeyLen - 1; curKeyPos >= 0; curFilePos--, curKeyPos-- ) { if ( curFilePos < 0 // если поз файла стала < 0 || _ini_szFileContent[nFilePointer]{curFilePos} != szKeyName[curKeyPos] // если символы из ключей не равны || _ini_szFileContent[nFilePointer]{curFilePos} == INI_STRING_DELIMITER // если символ из ключа это INI_STRING_DELIMITER ) { found = 0; // флаг, ключ не найден break; // конец сравнения } } // ---------------- if ( found != 0 ) // если указанный ключ найден в файле { // если найдено совпадение не целого ключа файла, а его окончания с указанным ключом if ( curFilePos >= 0 ) { switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_KEY_STARTS : {} default: continue; } } // ---------------- // текущая позиция в файле будет на 1 больше текущей позиции INI_DELIMITER curFilePos = _ini_nDelimPos[nFilePointer][kPos] + 1; // ищем позицию начала значения, она будет помещена в curFilePos for ( ; ; curFilePos++ ) { if ( curFilePos >= _ini_nFileSize[nFilePointer] ) break; switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_SPACE_CHARS : continue; // если это пробельный символ, перейдем к след. символу default : break; // если это другой символ } } // ---------------- // ---------------- new strValue[INI_INTEGER_SIZE]; // временная строка для численного значения // скопируем посимвольно в strValue значение ключа из файла // воспользуемся созданной переменной found как позицией в возвращаемом значении for ( found = 0; found < INI_INTEGER_SIZE; found++, curFilePos++ ) { switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_NUMBER_ENDS : // если это символ конца численного значения { strValue[found] = 0; // запишем символ конца строки break; // конец копирования } default : // копируем символ из файла в strValue strValue[found] = _ini_szFileContent[nFilePointer]{curFilePos}; } } strValue[INI_INTEGER_SIZE - 1] = 0; // на всякий случай обрежем правильно строку nReturnValue = strval(strValue); // запишем в nReturnValue численное значение ключа return INI_OK; // ---------------- } // ---------------- } // ---------------- // ---------------- return INI_KEY_NOT_FOUND; // ---------------- } /* Получает из открытого INI файла дробное численное значение указанного ключа. ПОДРОБНЕЕ Парсер ищет в ОЗУ в контенте файла указанный ключ и помещает в fReturnValue его дробное значение. fReturnValue нужно создать заранее. Имя ключа в файле может быть любой длины, а также может содержать любые символы, кроме 2 символов конца строки \r и \n. Значение может быть только фиксированной длины, которая равна INI_FLOAT_SIZE - 1. Парсер не видит пробелы и знаки табуляции вокруг имени ключа/значения, он считает их отступами. ПАРАМЕТРЫ: nFilePointer ИД_открытого_файла, полученный от ini_openFile / ini_createFile szKeyName[] имя ключа fReturnValue сюда будет помещено значение ключа в виде дробного числа ВЕРНЕТ: код ошибки < 0 или 0 при успехе */ stock ini_getFloat ( nFilePointer, const szKeyName[], & Float: fReturnValue ) { // ---------------- if // если ИД открытого файла указан неверно ( nFilePointer < 0 || nFilePointer >= INI_MAX_OPENED_FILES || _ini_nSlotUsed[nFilePointer] != 1 ) return INI_WRONG_SLOT; // вернуть код: неверный указатель на открытый файл // ---------------- // ---------------- new nKeyLen = strlen(szKeyName); // узнаем длину имени указанного ключа if ( nKeyLen <= 0 ) // если указан пустой ключ return INI_KEY_NOT_FOUND; // ---------------- // ---------------- for // перебор и сравнение всех ключей файла с указанным ключом ( new kPos = 0, curFilePos, found = 0; kPos < _ini_nKeysCount[nFilePointer]; kPos++ ) { // ---------------- found = 0; // флаг, найдена ли позиция конца ключа = 0 for // ищем позицию конца ключа ( curFilePos = _ini_nDelimPos[nFilePointer][kPos] - 1; // текущ. поз. файла = поз. текущ. INI_DELIMITER - 1 curFilePos >= 0; // продолжать пока поз. файла >= 0 curFilePos-- // после каждого повтора текущ. поз. файла -= 1 ) { switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) // узнаем что за символ в текущ. поз. файла { case INI_SPACE_CHARS : continue; // если это пробельный символ, перейдем к пред. символу файла case INI_STRING_DELIMITER : break; // если это конец строки default : // если это другой символ { found = 1; // позиция конца ключа найдена break; // конец цикла } } } // если позиция конца ключа не найдена, переход к след. позиции INI_DELIMITER if ( found != 1 ) continue; // ---------------- // сравниваем посимвольно текущий ключ файла и указанный ключ for ( new curKeyPos = nKeyLen - 1; curKeyPos >= 0; curFilePos--, curKeyPos-- ) { if ( curFilePos < 0 // если поз файла стала < 0 || _ini_szFileContent[nFilePointer]{curFilePos} != szKeyName[curKeyPos] // если символы из ключей не равны || _ini_szFileContent[nFilePointer]{curFilePos} == INI_STRING_DELIMITER // если символ из ключа это INI_STRING_DELIMITER ) { found = 0; // флаг, ключ не найден break; // конец сравнения } } // ---------------- if ( found != 0 ) // если указанный ключ найден в файле { // если найдено совпадение не целого ключа файла, а его окончания с указанным ключом if ( curFilePos >= 0 ) { switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_KEY_STARTS : {} default: continue; } } // ---------------- // текущая позиция в файле будет на 1 больше текущей позиции INI_DELIMITER curFilePos = _ini_nDelimPos[nFilePointer][kPos] + 1; // ищем позицию начала значения, она будет помещена в curFilePos for ( ; ; curFilePos++ ) { if ( curFilePos >= _ini_nFileSize[nFilePointer] ) break; switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_SPACE_CHARS : continue; // если это пробельный символ, перейдем к след. символу default : break; // если это другой символ } } // ---------------- // ---------------- new strValue[INI_FLOAT_SIZE]; // временная строка для дробного значения // скопируем посимвольно в strValue значение ключа из файла // воспользуемся созданной переменной found как позицией в возвращаемом значении for ( found = 0; found < INI_INTEGER_SIZE; found++, curFilePos++ ) { switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_NUMBER_ENDS : // если это символ конца численного значения { strValue[found] = 0; // запишем символ конца строки break; // конец копирования } default : // копируем символ из файла в strValue strValue[found] = _ini_szFileContent[nFilePointer]{curFilePos}; } } strValue[INI_FLOAT_SIZE - 1] = 0; // на всякий случай обрежем правильно строку fReturnValue = floatstr(strValue); // запишем в fReturnValue дробное значение ключа return INI_OK; // ---------------- } // ---------------- } // ---------------- // ---------------- return INI_KEY_NOT_FOUND; // ---------------- } /* Изменяет/добавляет в открытый INI файл указанный ключ и его значение. ПОДРОБНЕЕ Парсер ищет в ОЗУ в контенте файла указанный ключ и изменяет его строковое значение на szKeyValue. Форматирование файла не меняется. Если только указанное имя ключа не было найдено, тогда ключ и значение будут добавлены в конец файла. Имя ключа/значение в файле может быть любой длины, а также может содержать любые символы, кроме 2 символов конца строки \r и \n. Если эти символы есть в имени ключа или в значении, вы должны должны хорошо знать и осознавать последствия. ПАРАМЕТРЫ: nFilePointer ИД_открытого_файла, полученный от ini_openFile / ini_createFile szKeyName[] имя ключа szKeyValue[] строка со значением ключа ВЕРНЕТ: код ошибки < 0 или 0 при успехе */ stock ini_setString ( nFilePointer, const szKeyName[], const szKeyValue[] ) { // ---------------- if // если ИД открытого файла указан неверно ( nFilePointer < 0 || nFilePointer >= INI_MAX_OPENED_FILES || _ini_nSlotUsed[nFilePointer] != 1 ) return INI_WRONG_SLOT; // вернуть код: неверный указатель на открытый файл // ---------------- // ---------------- new nKeyLen = strlen(szKeyName); // узнаем длину имени указанного ключа if ( nKeyLen <= 0 ) // если указан пустой ключ return INI_KEY_NOT_FOUND; // ---------------- // ---------------- for // перебор и сравнение всех ключей файла с указанным ключом ( new kPos = 0, curFilePos, found; kPos < _ini_nKeysCount[nFilePointer]; kPos++ ) { // ---------------- found = 0; // флаг, найдена ли позиция конца ключа = 0 for // ищем позицию конца ключа ( curFilePos = _ini_nDelimPos[nFilePointer][kPos] - 1; // текущ. поз. файла = поз. текущ. INI_DELIMITER - 1 curFilePos >= 0; // продолжать пока поз. файла >= 0 curFilePos-- // после каждого повтора текущ. поз. файла -= 1 ) { switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) // узнаем что за символ в текущ. поз. файла { case INI_SPACE_CHARS : continue; // если это пробельный символ, перейдем к пред. символу файла case INI_STRING_DELIMITER : break; // если это конец строки default : // если это другой символ { found = 1; // позиция конца ключа найдена break; // конец цикла } } } // если позиция конца ключа не найдена, переход к след. позиции INI_DELIMITER if ( found != 1 ) continue; // ---------------- // сравниваем посимвольно текущий ключ файла и указанный ключ for ( new curKeyPos = nKeyLen - 1; curKeyPos >= 0; curFilePos--, curKeyPos-- ) { if ( curFilePos < 0 // если поз файла стала < 0 || _ini_szFileContent[nFilePointer]{curFilePos} != szKeyName[curKeyPos] // если символы из ключей не равны || _ini_szFileContent[nFilePointer]{curFilePos} == INI_STRING_DELIMITER // если символ из ключа это INI_STRING_DELIMITER ) { found = 0; // флаг, ключ не найден break; // конец сравнения } } if ( found != 0 ) // если указанный ключ НАЙДЕН в файле { // если найдено совпадение не целого ключа файла, а его окончания с указанным ключом if ( curFilePos >= 0 ) { switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_KEY_STARTS : {} default: continue; } } // ---------------- // текущая позиция в файле будет на 1 больше текущей позиции INI_DELIMITER curFilePos = _ini_nDelimPos[nFilePointer][kPos] + 1; // ищем позицию начала значения, она будет помещена в curFilePos for ( ; ; curFilePos++ ) { if ( curFilePos >= _ini_nFileSize[nFilePointer] ) break; switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_SPACE_CHARS : continue; // если это пробельный символ, перейдем к след. символу default : break; // если это другой символ } } // ---------------- // ---------------- new nValueLen = strlen(szKeyValue); // узнаем размер значения указанного ключа // если будущий размер файла превышает лимит if ( ( curFilePos + nValueLen ) >= INI_MAX_FILE_SIZE ) return INI_TOO_LARGE_FILE; // вернем код ошибки о переполнении файла // ---------------- // ---------------- new fileValueStartPos = curFilePos; // сохраним позицию начала значения // ищем позицию конца значения, она будет помещена в curFilePos for ( ; ; curFilePos++ ) { if ( curFilePos >= _ini_nFileSize[nFilePointer] ) break; switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_STRING_ENDS : break; // если это конец строки - стоп default : continue; // если это другой символ, перейдем к след. символу } } // вычислим смещение оставшихся позиций для INI_DELIMITER после изменения значения new filePosOffset = nValueLen - ( /*текущ длина значения*/ curFilePos - fileValueStartPos ); // ---------------- if ( _ini_nFileBusy[nFilePointer] != 0 ) // если прямо сейчас файл изменяется другой функцией return INI_WRITE_ERROR; // вернем код ошибки при записи в файл // ---------------- _ini_nFileBusy[nFilePointer] = 1; // флаг: файл изменяется = 1 if ( filePosOffset != 0 ) // если длины старого и нового значений разные { if ( filePosOffset < 0 ) // если длина нового значения меньше { for // копируем символы, стоящие после текущего значения на их новые места, ( // которые теперь будут ближе к началу файла ; curFilePos < _ini_nFileSize[nFilePointer]; curFilePos++ ) _ini_szFileContent[nFilePointer]{ curFilePos + filePosOffset } = _ini_szFileContent[nFilePointer]{curFilePos}; } else if ( filePosOffset > 0 ) // если длина нового значения больше { new fileValueEndPos = curFilePos; for // копируем символы, стоящие после текущего значения на их новые места, ( // начиная с конца файла curFilePos = _ini_nFileSize[nFilePointer] - 1; curFilePos >= fileValueEndPos; curFilePos-- ) _ini_szFileContent[nFilePointer]{ curFilePos + filePosOffset } = _ini_szFileContent[nFilePointer]{curFilePos}; } // изменим позиции всех INI_DELIMITER, которые находились после текущего INI_DELIMITER for ( kPos++; kPos < _ini_nKeysCount[nFilePointer]; kPos++ ) _ini_nDelimPos[nFilePointer][kPos] += filePosOffset; _ini_nFileSize[nFilePointer] += filePosOffset; // изменим размер файла _ini_szFileContent[nFilePointer]{ _ini_nFileSize[nFilePointer] } = 0; // конец строки для конца файла } curFilePos = fileValueStartPos; // текущ поз файла = поз начала старого значения for // запишем новое значение поверх старого ( new valuePos = 0; valuePos < nValueLen; curFilePos++, valuePos++ ) _ini_szFileContent[nFilePointer]{curFilePos} = szKeyValue[valuePos]; _ini_nFileChanged[nFilePointer] = 1; // флаг: файл изменен = 1 _ini_nFileBusy[nFilePointer] = 0; // флаг: файл изменяется = 0 return INI_OK; // ---------------- } } // ---------------- // // если указанный ключ НЕ НАЙДЕН в файле // // ---------------- new nValueLen = strlen(szKeyValue); // узнаем размер значения ключа // если будущий размер файла превышает лимит if ( ( _ini_nFileSize[nFilePointer] + 5 + nKeyLen + nValueLen ) >= INI_MAX_FILE_SIZE ) return INI_TOO_LARGE_FILE; // вернем код ошибки о переполнении файла // ---------------- // ---------------- if ( _ini_nFileBusy[nFilePointer] != 0 ) // если прямо сейчас файл изменяется другой функцией return INI_WRITE_ERROR; // вернем код ошибки при записи в файл _ini_nFileBusy[nFilePointer] = 1; // флаг: файл изменяется = 1 // ---------------- // ---------------- if // если последний символ файла не является разделителем строк ( _ini_nFileSize[nFilePointer] > 0 && _ini_szFileContent[nFilePointer]{ _ini_nFileSize[nFilePointer] - 1 } != INI_STRING_DELIMITER ) { // вставим в конец файла перевод каретки и разделитель строк _ini_szFileContent[nFilePointer]{ _ini_nFileSize[nFilePointer] } = '\r'; _ini_szFileContent[nFilePointer]{ _ini_nFileSize[nFilePointer] + 1 } = INI_STRING_DELIMITER; _ini_nFileSize[nFilePointer] += 2; // увеличим размер файла на 2 } new curFilePos, strPos; // будут временным хранилищами позиций в файле/ключе/значении for // добавим посимвольно имя ключа в файл ( curFilePos = _ini_nFileSize[nFilePointer], strPos = 0; strPos < nKeyLen; curFilePos++, strPos++ ) _ini_szFileContent[nFilePointer]{curFilePos} = szKeyName[strPos]; _ini_szFileContent[nFilePointer]{ curFilePos++ } = ' '; // после ключа добавим пробел _ini_nDelimPos[nFilePointer][ _ini_nKeysCount[nFilePointer] ] = curFilePos; // добавим новую позицию INI_DELIMITER _ini_nKeysCount[nFilePointer]++; // кол-во ключей в файле +1 _ini_szFileContent[nFilePointer]{ curFilePos++ } = INI_DELIMITER; // после пробела выше добавим INI_DELIMITER _ini_szFileContent[nFilePointer]{ curFilePos++ } = ' '; // после INI_DELIMITER добавим пробел // добавим посимвольно значение ключа в файл for ( strPos = 0; strPos < nValueLen; curFilePos++, strPos++ ) _ini_szFileContent[nFilePointer]{curFilePos} = szKeyValue[strPos]; _ini_szFileContent[nFilePointer]{curFilePos} = 0; // добавим символ конца строки _ini_nFileSize[nFilePointer] = curFilePos; // изменим размер файла _ini_nFileChanged[nFilePointer] = 1; // флаг: файл изменен = 1 _ini_nFileBusy[nFilePointer] = 0; // флаг: файл изменяется = 0 return INI_OK; // ---------------- } /* Изменяет/добавляет в открытый INI файл указанный ключ и его целочисленное значение. ПОДРОБНЕЕ Парсер ищет в ОЗУ в контенте файла указанный ключ и изменяет его целочисленное значение на nKeyValue. Форматирование файла не меняется, если только указанное имя ключа не было найдено, тогда ключ и значение будут добавлены в конец файла. Имя ключа в файле может быть любой длины, а также может содержать любые символы, кроме 2 символов конца строки \r и \n. Если вы в качестве значения указываете число больше, чем cellmax или меньше, чем cellmin, вы должны должны хорошо знать и осознавать последствия. ПАРАМЕТРЫ: nFilePointer ИД_открытого_файла, полученный от ini_openFile / ini_createFile szKeyName[] имя ключа nKeyValue целочисленное значение ключа ВЕРНЕТ: код ошибки < 0 или 0 при успехе */ stock ini_setInteger ( nFilePointer, const szKeyName[], nKeyValue ) { // ---------------- if // если ИД открытого файла указан неверно ( nFilePointer < 0 || nFilePointer >= INI_MAX_OPENED_FILES || _ini_nSlotUsed[nFilePointer] != 1 ) return INI_WRONG_SLOT; // вернуть код: неверный указатель на открытый файл // ---------------- // ---------------- new nKeyLen = strlen(szKeyName); // узнаем длину имени указанного ключа if ( nKeyLen <= 0 ) // если указан пустой ключ return INI_KEY_NOT_FOUND; // ---------------- // ---------------- for // перебор и сравнение всех ключей файла с указанным ключом ( new kPos = 0, curFilePos, found; kPos < _ini_nKeysCount[nFilePointer]; kPos++ ) { // ---------------- found = 0; // флаг, найдена ли позиция конца ключа = 0 for // ищем позицию конца ключа ( curFilePos = _ini_nDelimPos[nFilePointer][kPos] - 1; // текущ. поз. файла = поз. текущ. INI_DELIMITER - 1 curFilePos >= 0; // продолжать пока поз. файла >= 0 curFilePos-- // после каждого повтора текущ. поз. файла -= 1 ) { switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) // узнаем что за символ в текущ. поз. файла { case INI_SPACE_CHARS : continue; // если это пробельный символ, перейдем к пред. символу файла case INI_STRING_DELIMITER : break; // если это конец строки default : // если это другой символ { found = 1; // позиция конца ключа найдена break; // конец цикла } } } // если позиция конца ключа не найдена, переход к след. позиции INI_DELIMITER if ( found != 1 ) continue; // ---------------- // сравниваем посимвольно текущий ключ файла и указанный ключ for ( new curKeyPos = nKeyLen - 1; curKeyPos >= 0; curFilePos--, curKeyPos-- ) { if ( curFilePos < 0 // если поз файла стала < 0 || _ini_szFileContent[nFilePointer]{curFilePos} != szKeyName[curKeyPos] // если символы из ключей не равны || _ini_szFileContent[nFilePointer]{curFilePos} == INI_STRING_DELIMITER // если символ из ключа это INI_STRING_DELIMITER ) { found = 0; // флаг, ключ не найден break; // конец сравнения } } if ( found != 0 ) // если указанный ключ НАЙДЕН в файле { // если найдено совпадение не целого ключа файла, а его окончания с указанным ключом if ( curFilePos >= 0 ) { switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_KEY_STARTS : {} default: continue; } } // ---------------- // текущая позиция в файле будет на 1 больше текущей позиции INI_DELIMITER curFilePos = _ini_nDelimPos[nFilePointer][kPos] + 1; // ищем позицию начала значения, она будет помещена в curFilePos for ( ; ; curFilePos++ ) { if ( curFilePos >= _ini_nFileSize[nFilePointer] ) break; switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_SPACE_CHARS : continue; // если это пробельный символ, перейдем к след. символу default : break; // если это другой символ } } // ---------------- // ---------------- new szKeyValue[INI_INTEGER_SIZE]; // создадим строку для хранения целочисленного значения format( szKeyValue, INI_INTEGER_SIZE, "%i", nKeyValue ); // ---------------- // ---------------- new nValueLen = strlen(szKeyValue); // узнаем размер значения указанного ключа // если будущий размер файла превышает лимит if ( ( curFilePos + nValueLen ) >= INI_MAX_FILE_SIZE ) return INI_TOO_LARGE_FILE; // вернем код ошибки о переполнении файла // ---------------- // ---------------- new fileValueStartPos = curFilePos; // сохраним позицию начала значения // ищем позицию конца значения, она будет помещена в curFilePos for ( ; ; curFilePos++ ) { if ( curFilePos >= _ini_nFileSize[nFilePointer] ) break; switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_NUMBER_ENDS : break; // если это конец числа - стоп default : continue; // если это другой символ, перейдем к след. символу } } // вычислим смещение оставшихся позиций для INI_DELIMITER после изменения значения new filePosOffset = nValueLen - ( /*текущ длина значения*/ curFilePos - fileValueStartPos ); // ---------------- if ( _ini_nFileBusy[nFilePointer] != 0 ) // если прямо сейчас файл изменяется другой функцией return INI_WRITE_ERROR; // вернем код ошибки при записи в файл // ---------------- _ini_nFileBusy[nFilePointer] = 1; // флаг: файл изменяется = 1 if ( filePosOffset != 0 ) // если длины старого и нового значений разные { if ( filePosOffset < 0 ) // если длина нового значения меньше { for // копируем символы, стоящие после текущего значения на их новые места, ( // которые теперь будут ближе к началу файла ; curFilePos < _ini_nFileSize[nFilePointer]; curFilePos++ ) _ini_szFileContent[nFilePointer]{ curFilePos + filePosOffset } = _ini_szFileContent[nFilePointer]{curFilePos}; } else if ( filePosOffset > 0 ) // если длина нового значения больше { new fileValueEndPos = curFilePos; for // копируем символы, стоящие после текущего значения на их новые места, ( // начиная с конца файла curFilePos = _ini_nFileSize[nFilePointer] - 1; curFilePos >= fileValueEndPos; curFilePos-- ) _ini_szFileContent[nFilePointer]{ curFilePos + filePosOffset } = _ini_szFileContent[nFilePointer]{curFilePos}; } // изменим позиции всех INI_DELIMITER, которые находились после текущего INI_DELIMITER for ( kPos++; kPos < _ini_nKeysCount[nFilePointer]; kPos++ ) _ini_nDelimPos[nFilePointer][kPos] += filePosOffset; _ini_nFileSize[nFilePointer] += filePosOffset; // изменим размер файла _ini_szFileContent[nFilePointer]{ _ini_nFileSize[nFilePointer] } = 0; // конец строки для конца файла } curFilePos = fileValueStartPos; // текущ поз файла = поз начала старого значения for // запишем новое значение поверх старого ( new valuePos = 0; valuePos < nValueLen; curFilePos++, valuePos++ ) _ini_szFileContent[nFilePointer]{curFilePos} = szKeyValue[valuePos]; _ini_nFileChanged[nFilePointer] = 1; // флаг: файл изменен = 1 _ini_nFileBusy[nFilePointer] = 0; // флаг: файл изменяется = 0 return INI_OK; // ---------------- } } // ---------------- // // если указанный ключ НЕ НАЙДЕН в файле // // ---------------- new szKeyValue[INI_INTEGER_SIZE]; // создадим строку для хранения целочисленного значения format( szKeyValue, INI_INTEGER_SIZE, "%i", nKeyValue ); // ---------------- // ---------------- new nValueLen = strlen(szKeyValue); // узнаем размер значения ключа // если будущий размер файла превышает лимит if ( ( _ini_nFileSize[nFilePointer] + 5 + nKeyLen + nValueLen ) >= INI_MAX_FILE_SIZE ) return INI_TOO_LARGE_FILE; // вернем код ошибки о переполнении файла // ---------------- // ---------------- if ( _ini_nFileBusy[nFilePointer] != 0 ) // если прямо сейчас файл изменяется другой функцией return INI_WRITE_ERROR; // вернем код ошибки при записи в файл _ini_nFileBusy[nFilePointer] = 1; // флаг: файл изменяется = 1 // ---------------- // ---------------- if // если последний символ файла не является разделителем строк ( _ini_nFileSize[nFilePointer] > 0 && _ini_szFileContent[nFilePointer]{ _ini_nFileSize[nFilePointer] - 1 } != INI_STRING_DELIMITER ) { // вставим в конец файла перевод каретки и разделитель строк _ini_szFileContent[nFilePointer]{ _ini_nFileSize[nFilePointer] } = '\r'; _ini_szFileContent[nFilePointer]{ _ini_nFileSize[nFilePointer] + 1 } = INI_STRING_DELIMITER; _ini_nFileSize[nFilePointer] += 2; // увеличим размер файла на 2 } new curFilePos, strPos; // будут временным хранилищами позиций в файле/ключе/значении for // добавим посимвольно имя ключа в файл ( curFilePos = _ini_nFileSize[nFilePointer], strPos = 0; strPos < nKeyLen; curFilePos++, strPos++ ) _ini_szFileContent[nFilePointer]{curFilePos} = szKeyName[strPos]; _ini_szFileContent[nFilePointer]{ curFilePos++ } = ' '; // после ключа добавим пробел _ini_nDelimPos[nFilePointer][ _ini_nKeysCount[nFilePointer] ] = curFilePos; // добавим новую позицию INI_DELIMITER _ini_nKeysCount[nFilePointer]++; // кол-во ключей в файле +1 _ini_szFileContent[nFilePointer]{ curFilePos++ } = INI_DELIMITER; // после пробела выше добавим INI_DELIMITER _ini_szFileContent[nFilePointer]{ curFilePos++ } = ' '; // после INI_DELIMITER добавим пробел // добавим посимвольно значение ключа в файл for ( strPos = 0; strPos < nValueLen; curFilePos++, strPos++ ) _ini_szFileContent[nFilePointer]{curFilePos} = szKeyValue[strPos]; _ini_szFileContent[nFilePointer]{curFilePos} = 0; // добавим символ конца строки _ini_nFileSize[nFilePointer] = curFilePos; // изменим размер файла _ini_nFileChanged[nFilePointer] = 1; // флаг: файл изменен = 1 _ini_nFileBusy[nFilePointer] = 0; // флаг: файл изменяется = 0 return INI_OK; // ---------------- } /* Изменяет/добавляет в открытый INI файл указанный ключ и его дробное численное значение. ПОДРОБНЕЕ Парсер ищет в ОЗУ в контенте файла указанный ключ и изменяет его дробное значение на fKeyValue. Форматирование файла не меняется, если только указанное имя ключа не было найдено, тогда ключ и значение будут добавлены в конец файла. Имя ключа в файле может быть любой длины, а также может содержать любые символы, кроме 2 символов конца строки \r и \n. Если вы в качестве значения указываете очень большое/маленькое дробное число, вы должны хорошо знать и осознавать последствия. ПАРАМЕТРЫ: nFilePointer ИД_открытого_файла, полученный от ini_openFile / ini_createFile szKeyName[] имя ключа fKeyValue дробное численное значение ключа ВЕРНЕТ: код ошибки < 0 или 0 при успехе */ stock ini_setFloat ( nFilePointer, const szKeyName[], Float: fKeyValue ) { // ---------------- if // если ИД открытого файла указан неверно ( nFilePointer < 0 || nFilePointer >= INI_MAX_OPENED_FILES || _ini_nSlotUsed[nFilePointer] != 1 ) return INI_WRONG_SLOT; // вернуть код: неверный указатель на открытый файл // ---------------- // ---------------- new nKeyLen = strlen(szKeyName); // узнаем длину имени указанного ключа if ( nKeyLen <= 0 ) // если указан пустой ключ return INI_KEY_NOT_FOUND; // ---------------- // ---------------- for // перебор и сравнение всех ключей файла с указанным ключом ( new kPos = 0, curFilePos, found; kPos < _ini_nKeysCount[nFilePointer]; kPos++ ) { // ---------------- found = 0; // флаг, найдена ли позиция конца ключа = 0 for // ищем позицию конца ключа ( curFilePos = _ini_nDelimPos[nFilePointer][kPos] - 1; // текущ. поз. файла = поз. текущ. INI_DELIMITER - 1 curFilePos >= 0; // продолжать пока поз. файла >= 0 curFilePos-- // после каждого повтора текущ. поз. файла -= 1 ) { switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) // узнаем что за символ в текущ. поз. файла { case INI_SPACE_CHARS : continue; // если это пробельный символ, перейдем к пред. символу файла case INI_STRING_DELIMITER : break; // если это конец строки default : // если это другой символ { found = 1; // позиция конца ключа найдена break; // конец цикла } } } // если позиция конца ключа не найдена, переход к след. позиции INI_DELIMITER if ( found != 1 ) continue; // ---------------- // сравниваем посимвольно текущий ключ файла и указанный ключ for ( new curKeyPos = nKeyLen - 1; curKeyPos >= 0; curFilePos--, curKeyPos-- ) { if ( curFilePos < 0 // если поз файла стала < 0 || _ini_szFileContent[nFilePointer]{curFilePos} != szKeyName[curKeyPos] // если символы из ключей не равны || _ini_szFileContent[nFilePointer]{curFilePos} == INI_STRING_DELIMITER // если символ из ключа это INI_STRING_DELIMITER ) { found = 0; // флаг, ключ не найден break; // конец сравнения } } if ( found != 0 ) // если указанный ключ НАЙДЕН в файле { // если найдено совпадение не целого ключа файла, а его окончания с указанным ключом if ( curFilePos >= 0 ) { switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_KEY_STARTS : {} default: continue; } } // ---------------- // текущая позиция в файле будет на 1 больше текущей позиции INI_DELIMITER curFilePos = _ini_nDelimPos[nFilePointer][kPos] + 1; // ищем позицию начала значения, она будет помещена в curFilePos for ( ; ; curFilePos++ ) { if ( curFilePos >= _ini_nFileSize[nFilePointer] ) break; switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_SPACE_CHARS : continue; // если это пробельный символ, перейдем к след. символу default : break; // если это другой символ } } // ---------------- // ---------------- new szKeyValue[INI_FLOAT_SIZE]; // создадим строку для хранения дробного значения format( szKeyValue, INI_FLOAT_SIZE, "%f", fKeyValue ); // поместим строковое значение fKeyValue в szKeyValue // ---------------- // ---------------- new nValueLen = strlen(szKeyValue); // узнаем размер значения указанного ключа // если будущий размер файла превышает лимит if ( ( curFilePos + nValueLen ) >= INI_MAX_FILE_SIZE ) return INI_TOO_LARGE_FILE; // вернем код ошибки о переполнении файла // ---------------- // ---------------- new fileValueStartPos = curFilePos; // сохраним позицию начала значения // ищем позицию конца значения, она будет помещена в curFilePos for ( ; ; curFilePos++ ) { if ( curFilePos >= _ini_nFileSize[nFilePointer] ) break; switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_NUMBER_ENDS : break; // если это конец числа - стоп default : continue; // если это другой символ, перейдем к след. символу } } // вычислим смещение оставшихся позиций для INI_DELIMITER после изменения значения new filePosOffset = nValueLen - ( /*текущ длина значения*/ curFilePos - fileValueStartPos ); // ---------------- if ( _ini_nFileBusy[nFilePointer] != 0 ) // если прямо сейчас файл изменяется другой функцией return INI_WRITE_ERROR; // вернем код ошибки при записи в файл // ---------------- _ini_nFileBusy[nFilePointer] = 1; // флаг: файл изменяется = 1 if ( filePosOffset != 0 ) // если длины старого и нового значений разные { if ( filePosOffset < 0 ) // если длина нового значения меньше { for // копируем символы, стоящие после текущего значения на их новые места, ( // которые теперь будут ближе к началу файла ; curFilePos < _ini_nFileSize[nFilePointer]; curFilePos++ ) _ini_szFileContent[nFilePointer]{ curFilePos + filePosOffset } = _ini_szFileContent[nFilePointer]{curFilePos}; } else if ( filePosOffset > 0 ) // если длина нового значения больше { new fileValueEndPos = curFilePos; for // копируем символы, стоящие после текущего значения на их новые места, ( // начиная с конца файла curFilePos = _ini_nFileSize[nFilePointer] - 1; curFilePos >= fileValueEndPos; curFilePos-- ) _ini_szFileContent[nFilePointer]{ curFilePos + filePosOffset } = _ini_szFileContent[nFilePointer]{curFilePos}; } // изменим позиции всех INI_DELIMITER, которые находились после текущего INI_DELIMITER for ( kPos++; kPos < _ini_nKeysCount[nFilePointer]; kPos++ ) _ini_nDelimPos[nFilePointer][kPos] += filePosOffset; _ini_nFileSize[nFilePointer] += filePosOffset; // изменим размер файла _ini_szFileContent[nFilePointer]{ _ini_nFileSize[nFilePointer] } = 0; // конец строки для конца файла } curFilePos = fileValueStartPos; // текущ поз файла = поз начала старого значения for // запишем новое значение поверх старого ( new valuePos = 0; valuePos < nValueLen; curFilePos++, valuePos++ ) _ini_szFileContent[nFilePointer]{curFilePos} = szKeyValue[valuePos]; _ini_nFileChanged[nFilePointer] = 1; // флаг: файл изменен = 1 _ini_nFileBusy[nFilePointer] = 0; // флаг: файл изменяется = 0 return INI_OK; // ---------------- } } // ---------------- // // если указанный ключ НЕ НАЙДЕН в файле // // ---------------- new szKeyValue[INI_FLOAT_SIZE]; // создадим строку для хранения дробного значения format( szKeyValue, INI_FLOAT_SIZE, "%f", fKeyValue ); // поместим строковое значение fKeyValue в szKeyValue // ---------------- // ---------------- new nValueLen = strlen(szKeyValue); // узнаем размер значения ключа // если будущий размер файла превышает лимит if ( ( _ini_nFileSize[nFilePointer] + 5 + nKeyLen + nValueLen ) >= INI_MAX_FILE_SIZE ) return INI_TOO_LARGE_FILE; // вернем код ошибки о переполнении файла // ---------------- // ---------------- if ( _ini_nFileBusy[nFilePointer] != 0 ) // если прямо сейчас файл изменяется другой функцией return INI_WRITE_ERROR; // вернем код ошибки при записи в файл _ini_nFileBusy[nFilePointer] = 1; // флаг: файл изменяется = 1 // ---------------- // ---------------- if // если последний символ файла не является разделителем строк ( _ini_nFileSize[nFilePointer] > 0 && _ini_szFileContent[nFilePointer]{ _ini_nFileSize[nFilePointer] - 1 } != INI_STRING_DELIMITER ) { // вставим в конец файла перевод каретки и разделитель строк _ini_szFileContent[nFilePointer]{ _ini_nFileSize[nFilePointer] } = '\r'; _ini_szFileContent[nFilePointer]{ _ini_nFileSize[nFilePointer] + 1 } = INI_STRING_DELIMITER; _ini_nFileSize[nFilePointer] += 2; // увеличим размер файла на 2 } new curFilePos, strPos; // будут временным хранилищами позиций в файле/ключе/значении for // добавим посимвольно имя ключа в файл ( curFilePos = _ini_nFileSize[nFilePointer], strPos = 0; strPos < nKeyLen; curFilePos++, strPos++ ) _ini_szFileContent[nFilePointer]{curFilePos} = szKeyName[strPos]; _ini_szFileContent[nFilePointer]{ curFilePos++ } = ' '; // после ключа добавим пробел _ini_nDelimPos[nFilePointer][ _ini_nKeysCount[nFilePointer] ] = curFilePos; // добавим новую позицию INI_DELIMITER _ini_nKeysCount[nFilePointer]++; // кол-во ключей в файле +1 _ini_szFileContent[nFilePointer]{ curFilePos++ } = INI_DELIMITER; // после пробела выше добавим INI_DELIMITER _ini_szFileContent[nFilePointer]{ curFilePos++ } = ' '; // после INI_DELIMITER добавим пробел // добавим посимвольно значение ключа в файл for ( strPos = 0; strPos < nValueLen; curFilePos++, strPos++ ) _ini_szFileContent[nFilePointer]{curFilePos} = szKeyValue[strPos]; _ini_szFileContent[nFilePointer]{curFilePos} = 0; // добавим символ конца строки _ini_nFileSize[nFilePointer] = curFilePos; // изменим размер файла _ini_nFileChanged[nFilePointer] = 1; // флаг: файл изменен = 1 _ini_nFileBusy[nFilePointer] = 0; // флаг: файл изменяется = 0 return INI_OK; // ---------------- } /* Удаляет из открытого INI файла указанный ключ и его значение. ПОДРОБНЕЕ Парсер ищет в ОЗУ в контенте файла указанный ключ и удаляет найденную пару ключ/значение. Имя ключа/значение в файле может быть любой длины, а также может содержать любые символы, кроме 2 символов конца строки \r и \n. Если эти символы есть в имени ключа или в значении, вы должны должны хорошо знать и осознавать последствия. ПАРАМЕТРЫ: nFilePointer ИД_открытого_файла, полученный от ini_openFile / ini_createFile szKeyName[] имя ключа ВЕРНЕТ: код ошибки < 0 или 0 при успехе */ stock ini_removeKey ( nFilePointer, const szKeyName[] ) { // ---------------- if // если ИД открытого файла указан неверно ( nFilePointer < 0 || nFilePointer >= INI_MAX_OPENED_FILES || _ini_nSlotUsed[nFilePointer] != 1 ) return INI_WRONG_SLOT; // вернуть код: неверный указатель на открытый файл // ---------------- // ---------------- new nKeyLen = strlen(szKeyName); // узнаем длину имени указанного ключа if ( nKeyLen <= 0 ) // если указан пустой ключ return INI_KEY_NOT_FOUND; // ---------------- // ---------------- for // перебор и сравнение всех ключей файла с указанным ключом ( new kPos = 0, curFilePos, found; kPos < _ini_nKeysCount[nFilePointer]; kPos++ ) { // ---------------- found = 0; // флаг, найдена ли позиция конца ключа = 0 for // ищем позицию конца ключа ( curFilePos = _ini_nDelimPos[nFilePointer][kPos] - 1; // текущ. поз. файла = поз. текущ. INI_DELIMITER - 1 curFilePos >= 0; // продолжать пока поз. файла >= 0 curFilePos-- // после каждого повтора текущ. поз. файла -= 1 ) { switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) // узнаем что за символ в текущ. поз. файла { case INI_SPACE_CHARS : continue; // если это пробельный символ, перейдем к пред. символу файла case INI_STRING_DELIMITER : break; // если это конец строки default : // если это другой символ { found = 1; // позиция конца ключа найдена break; // конец цикла } } } // если позиция конца ключа не найдена, переход к след. позиции INI_DELIMITER if ( found != 1 ) continue; // ---------------- // сравниваем посимвольно текущий ключ файла и указанный ключ for ( new curKeyPos = nKeyLen - 1; curKeyPos >= 0; curFilePos--, curKeyPos-- ) { if ( curFilePos < 0 // если поз файла стала < 0 || _ini_szFileContent[nFilePointer]{curFilePos} != szKeyName[curKeyPos] // если символы из ключей не равны || _ini_szFileContent[nFilePointer]{curFilePos} == INI_STRING_DELIMITER // если символ из ключа это INI_STRING_DELIMITER ) { found = 0; // флаг, ключ не найден break; // конец сравнения } } if ( found != 0 ) // если указанный ключ НАЙДЕН в файле { // если найдено совпадение не целого ключа файла, а его окончания с указанным ключом if ( curFilePos >= 0 ) { switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_KEY_STARTS : {} default: continue; } } // сохраним позицию начала ключа new keyStartPos = ( curFilePos <= 0 ) ? 0 : curFilePos + 1; // ---------------- // текущая позиция в файле будет на 1 больше текущей позиции INI_DELIMITER curFilePos = _ini_nDelimPos[nFilePointer][kPos] + 1; // ищем позицию начала значения, она будет помещена в curFilePos for ( ; ; curFilePos++ ) { if ( curFilePos >= _ini_nFileSize[nFilePointer] ) break; switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_SPACE_CHARS : continue; // если это пробельный символ, перейдем к след. символу default : break; // если это другой символ } } // ---------------- // ---------------- // ищем позицию конца значения, она будет помещена в curFilePos for ( ; ; curFilePos++ ) { if ( curFilePos >= _ini_nFileSize[nFilePointer] ) break; switch ( _ini_szFileContent[nFilePointer]{curFilePos} ) { case INI_STRING_ENDS : break; // если это конец строки - стоп default : continue; // если это другой символ, перейдем к след. символу } } // вычислим смещение оставшихся позиций для INI_DELIMITER после изменения значения new filePosOffset = keyStartPos - curFilePos; // ---------------- if ( _ini_nFileBusy[nFilePointer] != 0 ) // если прямо сейчас файл изменяется другой функцией return INI_WRITE_ERROR; // вернем код ошибки при записи в файл // ---------------- _ini_nFileBusy[nFilePointer] = 1; // флаг: файл изменяется = 1 // затираем контент ключа, следующими за ним данными файла for ( ; curFilePos <= _ini_nFileSize[nFilePointer]; curFilePos++ ) _ini_szFileContent[nFilePointer]{ curFilePos + filePosOffset } = _ini_szFileContent[nFilePointer]{curFilePos}; // затираем текущий INI_DELIMITER, и меняем позиции последующих INI_DELIMITER for ( ; kPos < _ini_nKeysCount[nFilePointer]; kPos++ ) _ini_nDelimPos[nFilePointer][kPos] = _ini_nDelimPos[nFilePointer][kPos + 1] + filePosOffset; _ini_nKeysCount[nFilePointer]--; _ini_nFileSize[nFilePointer] += filePosOffset; // изменим размер файла _ini_szFileContent[nFilePointer]{ _ini_nFileSize[nFilePointer] } = 0; // конец строки для конца файла _ini_nFileChanged[nFilePointer] = 1; // флаг: файл изменен = 1 _ini_nFileBusy[nFilePointer] = 0; // флаг: файл изменяется = 0 return INI_OK; // ---------------- } } // ---------------- // // если указанный ключ НЕ НАЙДЕН в файле // // ---------------- return INI_KEY_NOT_FOUND; // ---------------- } /* Возвращает строку с описанием указанного кода ошибки на русском языке. ПОДРОБНЕЕ Если какая-то функция вам вернула не 0 (всё в порядке), а отрицательное значение, значит, имела место ошибка. Если вы хотите вывести в любой лог или в диалог человеческое описание этой ошибки, то передайте этой функции код ошибки и она вам вернет описание этой ошибки на русском языке. Описание ошибок довольно длинные и превышают размер в 128 символов, поэтому выводить эти описания в чате не рекомендуется! ПАРАМЕТРЫ: nErrorCode код ошибки, полученный от любой функции ВЕРНЕТ: строку с человеческим описанием ошибки, под указанным кодом ПРИМЕР: new ini = ini_openFile("несуществующий файл"); // пытаемся открыть несуществующий файл if ( ini < 0 ) print( ini_getErrorInfo(ini) ); else { new number, result = ini_getInteger( ini, "несуществующий ключ", number ); // пробуем получить значение несуществующего ключа if ( result < 0 ) print( ini_getErrorInfo(result) ); ini_closeFile(ini); } */ stock ini_getErrorInfo ( nErrorCode ) { if ( nErrorCode >= 0 ) return "Ошибок нет"; switch ( nErrorCode ) { case INI_FILE_NOT_FOUND : return "INI файл, указанный в `ini_openFile`, не существует, возможно, указан неверный путь к нему"; case INI_FILE_ALREADY_EXIST : return "INI файл, указанный в `ini_createFile`, уже существует, укажите другое имя/путь к файлу"; case INI_TOO_LARGE_FILE : return "Невозможно добавить новый ключ в INI файл, т.к. размер INI файла превысит допустимый лимит в " #INI_MAX_FILE_SIZE " символ(ов), или будет превышен лимит в " #INI_MAX_KEYS_IN_FILE " ключей"; case INI_WRONG_PATH_SIZE : return "Длина пути к INI файлу, указанного в `ini_openFile` / `ini_createFile`, превышает лимит в " #INI_MAX_FILENAME_SIZE " символ(ов)"; case INI_READ_ERROR : return "Ошибка при чтении INI файла с диска, возможно, файл занят другим процессом"; case INI_WRITE_ERROR : return "Ошибка при записи содержимого INI файла на диск, возможно, файл занят другим процессом"; case INI_NO_FREE_SLOT : return "Лимит в " #INI_MAX_OPENED_FILES " одновременно открытых INI файлов исчерпан, поэтому открыть/создать еще 1 файл нельзя, пока не закрыт хоть 1 из открытых файлов"; case INI_WRONG_SLOT : return "Указан неверный ID открытого INI файла, возможно, при открытии INI файла произошла ошибка, поэтому вместо ID файла вы получили код ошибки"; case INI_KEY_NOT_FOUND : return "Указанный ключ не найден в открытом INI файле"; case INI_WRONG_RETURN_SIZE : return "При попытке чтения строкового значения из INI файла, последний параметр `nSizeOfReturn` в `ini_getString` оказался <= 0, укажите вручную значение > 0 для него"; } return "Неизвестная ошибка"; }