| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987 |
- /**--------------------------------------------------------------------------**\
- ===========================
- Y Sever Includes - INI Core
- ===========================
- Description:
- Reads the INI and also exports a number of functions to other "classes" for
- easy reading of data files there.
- Legal:
- Version: MPL 1.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is the YSI ini include.
-
- The Initial Developer of the Original Code is Alex "Y_Less" Cole.
- Portions created by the Initial Developer are Copyright (C) 2011
- the Initial Developer. All Rights Reserved.
-
- Contributors:
- ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
-
- Thanks:
- JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
- ZeeX - Very productive conversations.
- koolk - IsPlayerinAreaEx code.
- TheAlpha - Danish translation.
- breadfish - German translation.
- Fireburn - Dutch translation.
- yom - French translation.
- 50p - Polish translation.
- Zamaroht - Spanish translation.
- Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
- for me to strive to better.
- Pixels^ - Running XScripters where the idea was born.
- Matite - Pestering me to release it and using it.
-
- Very special thanks to:
- Thiadmer - PAWN, whose limits continue to amaze me!
- Kye/Kalcor - SA:MP.
- SA:MP Team past, present and future - SA:MP.
-
- Version:
- 1.5
- Changelog:
- 07/01/13:
- Rewrote almost everything!
- Split in to multiple files.
- Added sections.
- 08/09/10:
- Started adding sscanf and file plugin compatibility.
- Added tagless data at the start of a file (dini compatible).
- Added new INI:file[tag]() syntax.
- Added options to default file load.
- Fixed bugs in default file load configuration.
- Modified to be stand alone.
- 20/02/08:
- Added INI_RemoveEntry.
- 18/08/07:
- Fixed bug reading identifiers starting with a tag (i.e. names).
- Added local file reading for non-serverwide broadcasting.
- Added tag passing instead of tag based functions option.
- Increased default pool size.
- 30/07/07:
- Added auto creation of non-existant files.
- 13/07/07:
- Fixed INI writing to actually work.
- Added support for blank lines in INIs decently and quickly.
- 25/06/07:
- Altered file write options to use lists.
- Added buffer overwriting for updating values.
- 24/06/07:
- Added file write options.
- 21/06/07:
- Added INI_NEW_LINE for future writing functions.
- 20/06/07:
- Added support for an optional parameter in broadcastfunc data.
- 15/04/07:
- Updated for more whitespaces.
- Added INI comment code.
- Added support for value-less entries.
- Modified entry extraction to use end of name location parameter.
- Removed INI_GetTagName, now done via INI_GetEntryName.
- 14/04/07:
- Updated header documentation with more than changelog.
- 24/03/07:
- First version.
- Functions:
- Public:
- -
- Core:
- -
- Stock:
- INI_Load - Loads an INI file using standard features.
- INI_ParseFile - Loads a file as an ini and distributes data.
- INI_GetEntryName - Gets the name of an INI item.
- INI_GetEntryText - Gets the value of an INI item.
- INI_Open - Opens an INI for writing.
- INI_Close - Closes an INI being written to.
- INI_SetTag - Sets a subheading in an INI fo subsequent writes.
- INI_WriteString - Writes a string to an INI.
- INI_WriteInt - Writes an int to an INI.
- INI_WriteFloat - Writes a float to an INI.
- INI_WriteHex - Writes a hex to an INI.
- INI_WriteBin - Writes a binary to an INI.
- INI_WriteBool - Writes a boolean to an INI.
- INI_RemoveEntry - Remove an entry from a file.
- Static:
- INI_WriteBuffer - Writes an INI's buffer to the file.
- INI_AddToBuffer - Adds a string to an INI buffer.
- Inline:
- INI_Int - Parse an integer INI entry.
- INI_Float - Parse a float INI entry.
- INI_Hex - Parse a hex INI entry.
- INI_Bin - Parse a binary INI entry.
- INI_Bool - Parse a binary INI entry.
- INI_String - Parse a string INI entry.
- API:
- -
- Callbacks:
- -
- Definitions:
- MAX_INI_TAG - Maximum length of an INI tagname.
- MAX_INI_ENTRY_NAME - Maximum length of an INI entry name.
- MAX_INI_ENTRY_TEXT - Maximum length of an INI's entries' value.
- MAX_INI_LINE - Maximum length of a line in a file.
- INI_NEW_LINE - String for new lines.
- INI_MAX_WRITES - Maximum concurrent files open for writing.
- MAX_INI_TAGS - Number of tags the buffer can hold data for at once.
- Enums:
- E_INI_WRITE - Storage for entries to be written.
- E_INI_TAGS - Data for tags with data.
- Macros:
- INI_Parse - Header for ini parsing functions.
- Tags:
- INI - Handle to an INI file being written to.
- Variables:
- Global:
- -
- Static:
- YSI_g_sINIWriteBuffer - Basic data to be written.
- YSI_g_sINIWritePos - Next slot to write to.
- YSI_g_sINITagPos - Next slot to add a tag to.
- YSI_g_sINICurrentTag - Pointer to the tag been writen to.
- YSI_g_sINIWriteTag - Data for tags,
- YSI_g_sINIWriteFile - Current files been written to.
- Commands:
- -
- Compile options:
- -
- Operators:
- -
- \**--------------------------------------------------------------------------**/
- /*
- ad88888ba
- d8" "8b ,d
- Y8, 88
- `Y8aaaaa, ,adPPYba, MM88MMM 88 88 8b,dPPYba,
- `"""""8b, a8P_____88 88 88 88 88P' "8a
- `8b 8PP""""""" 88 88 88 88 d8
- Y8a a8P "8b, ,aa 88, "8a, ,a88 88b, ,a8"
- "Y88888P" `"Ybbd8"' "Y888 `"YbbdP'Y8 88`YbbdP"'
- 88
- 88
-
- */
- enum E_INI_KV_ENTRY
- {
- E_INI_KV_ENTRY_NAME[MAX_INI_ENTRY_NAME],
- E_INI_KV_ENTRY_TEXT[MAX_INI_ENTRY_TEXT],
- E_INI_KV_ENTRY_NEXT
- }
- enum E_INI_TAGS
- {
- E_INI_TAGS_NAME[MAX_INI_TAG char],
- E_INI_TAGS_START,
- E_INI_TAGS_NEXT
- }
- _Y_INI_STATIC stock
- YSI_g_sINITmpBuffer[36],
- YSI_g_sINIWriteBuffer[INI_MAX_WRITES * INI_BUFFER_SIZE][E_INI_KV_ENTRY],
- YSI_g_sINIWritePos, // Pointer to the first free K/V slot.
- YSI_g_sINITagPos, // Pointer to the first free tag slot.
- YSI_g_sINITagBuffer[INI_MAX_WRITES * MAX_INI_TAGS][E_INI_TAGS],
- YSI_g_sINICurrentTag[INI:INI_MAX_WRITES],
- YSI_g_sINIStartTag[INI:INI_MAX_WRITES],
- YSI_g_sINIWriteFile[INI:INI_MAX_WRITES][YSI_MAX_STRING];
- forward bool:INI_WriteBuffer(INI:file);
- forward bool:INI_Flush();
- /*
- 88b d88
- 888b d888
- 88`8b d8'88
- 88 `8b d8' 88 ,adPPYYba, ,adPPYba, 8b,dPPYba, ,adPPYba, ,adPPYba,
- 88 `8b d8' 88 "" `Y8 a8" "" 88P' "Y8 a8" "8a I8[ ""
- 88 `8b d8' 88 ,adPPPPP88 8b 88 8b d8 `"Y8ba,
- 88 `888' 88 88, ,88 "8a, ,aa 88 "8a, ,a8" aa ]8I
- 88 `8' 88 `"8bbdP"Y8 `"Ybbd8"' 88 `"YbbdP"' `"YbbdP"'
- */
- #define INI_IsValid(%0) (0 <= _:(%0) < INI_MAX_WRITES && YSI_g_sINIWriteFile[(%0)][0])
- #define INI_WriteComments() \
- fwrite(buffer, ";"), \
- fwrite(buffer, sLine[p2s])
- #define INI_IsDeleted(%0) ((%0) != -1 && YSI_g_sINITagBuffer[(%0)][E_INI_TAGS_START] == cellmax)
- /*
- 88b d88 88 db 88888888ba 88
- 888b d888 "" d88b 88 "8b 88
- 88`8b d8'88 d8'`8b 88 ,8P 88
- 88 `8b d8' 88 ,adPPYYba, 88 8b,dPPYba, d8' `8b 88aaaaaa8P' 88
- 88 `8b d8' 88 "" `Y8 88 88P' `"8a d8YaaaaY8b 88""""""' 88
- 88 `8b d8' 88 ,adPPPPP88 88 88 88 d8""""""""8b 88 88
- 88 `888' 88 88, ,88 88 88 88 d8' `8b 88 88
- 88 `8' 88 `"8bbdP"Y8 88 88 88 d8' `8b 88 88
- */
- /**--------------------------------------------------------------------------**\
- <summary>INI_Open</summary>
- <param name="filename[]">INI file to open.</param>
- <returns>
- INI - handle to the file or INI_NO_FILE.
- </returns>
- <remarks>
- Doesn't actually open the file, just starts a new buffer if possible.
- </remarks>
- \**--------------------------------------------------------------------------**/
- stock INI:INI_Open(const filename[])
- {
- if (ftouch(filename) == -1)
- {
- P:W("INI_Open could not find or create file %s", filename);
- }
- P:3("INI:INI_Open called: \"%s\"", filename);
- new
- i;
- while (i != INI_MAX_WRITES && YSI_g_sINIWriteFile[INI:i][0]) ++i;
- if (i == INI_MAX_WRITES) return INI_NO_FILE;
- return
- strcpy(YSI_g_sINIWriteFile[INI:i], filename, YSI_MAX_STRING),
- // Reset tags.
- YSI_g_sINIStartTag[INI:i] = -1,
- YSI_g_sINICurrentTag[INI:i] = -1,
- INI:i;
- }
- /**--------------------------------------------------------------------------**\
- <summary>INI_Close</summary>
- <param name="INI:file">Handle to the ini to close.</param>
- <returns>
- -
- </returns>
- <remarks>
- Writes any outstanding buffer data to the file and ends the stream.
- </remarks>
- \**--------------------------------------------------------------------------**/
- stock INI_Close(INI:file)
- {
- P:3("INI_Close called: %i", _:file);
- if (INI_IsValid(file))
- {
- INI_WriteBuffer(file), // Used to check, now just flush by default.
- YSI_g_sINIWriteFile[file][0] = '\0';
- }
- }
- /**--------------------------------------------------------------------------**\
- <summary>INI_SetTag</summary>
- <param name="INI:file">INI file handle to write to.</param>
- <param name="tag[]">Name of the new file subsection for subsequent data to write to.</param>
- <returns>
- -
- </returns>
- <remarks>
- Sets a new [tag] section header. Subsequent data is written under this
- header. Uses lists for constant tag switching and checks the tag doesn't
- already exist.
- </remarks>
- \**--------------------------------------------------------------------------**/
- stock INI_SetTag(INI:file, const tag[])
- {
- P:3("INI_SetTag called: %i, \"%s\"", _:file, tag);
- if (INI_IsValid(file))
- {
- // Loop through the tags for this file.
- new
- cur = INI_GetTag(file, tag);
- if (cur != -1) return (YSI_g_sINICurrentTag[file] = cur);
- // May need some extra space.
- if (YSI_g_sINITagPos == -1 && !INI_Flush()) return -1;
- // Tag hasn't been written to yet this flush.
- return
- // Get a new tag.
- cur = YSI_g_sINITagPos,
- // Update the "free" list.
- YSI_g_sINITagPos = YSI_g_sINITagBuffer[cur][E_INI_TAGS_NEXT],
- // Add this tag to the current file's list.
- YSI_g_sINITagBuffer[cur][E_INI_TAGS_NEXT] = YSI_g_sINIStartTag[file],
- YSI_g_sINIStartTag[file] = cur,
- // Copy the name over.
- strpack(YSI_g_sINITagBuffer[cur][E_INI_TAGS_NAME], tag, MAX_INI_TAG char),
- // Set start points.
- YSI_g_sINITagBuffer[cur][E_INI_TAGS_START] = -1,
- YSI_g_sINICurrentTag[file] = cur;
- }
- return -1;
- }
- /**--------------------------------------------------------------------------**\
- <summary>INI_DeleteTag</summary>
- <param name="INI:file">INI file handle to write to.</param>
- <param name="tag[]">Name of the whole section to delete.</param>
- <returns>
- -
- </returns>
- <remarks>
- Removes a [tag] section from a file.
- </remarks>
- \**--------------------------------------------------------------------------**/
- stock INI_DeleteTag(INI:file, const tag[])
- {
- P:3("INI_DeleteTag called: %i, \"%s\"", _:file, tag);
- if (INI_IsValid(file))
- {
- // Save the tag currently being written to.
- new
- curTag = YSI_g_sINICurrentTag[file],
- tag2[MAX_INI_TAG];
- if (curTag != -1) strunpack(tag2, YSI_g_sINITagBuffer[curTag][E_INI_TAGS_NAME]);
- new
- // Get a pointer to the new tag.
- tp = INI_SetTag(file, tag),
- cur = YSI_g_sINITagBuffer[tp][E_INI_TAGS_START];
- // If there is anything in the tag, discard it. Accounts for "cellmax"
- // specials.
- while (0 <= cur < sizeof (YSI_g_sINIWriteBuffer)) cur = INI_FreeEntry(cur);
- // Now set it to the special "deleted" mark.
- YSI_g_sINITagBuffer[tp][E_INI_TAGS_START] = cellmax;
- // Reset the current tag, using a name not a pointer - we may have
- // flushed the buffer in the meantime and thus invalidated "curTag".
- YSI_g_sINICurrentTag[file] = (curTag == -1) ? -1 : INI_GetTag(file, tag2);
- }
- }
- /**--------------------------------------------------------------------------**\
- <summary>INI_RemoveEntry</summary>
- <param name="INI:file">File to write to.</param>
- <param name="name[]">Item to remove.</param>
- <returns>
- -
- </returns>
- <remarks>
- Wrapper for INI_AddToBuffer for removing data.
- </remarks>
- \**--------------------------------------------------------------------------**/
- stock INI_RemoveEntry(INI:file, name[])
- {
- P:3("INI_RemoveEntry called: %i, \"%s\"", _:file, name);
- return INI_AddToBuffer(file, name, NULL);
- }
- /*
- I8, 8 ,8I 88 88
- `8b d8b d8' "" ,d ""
- "8, ,8"8, ,8" 88
- Y8 8P Y8 8P 8b,dPPYba, 88 MM88MMM 88 8b,dPPYba, ,adPPYb,d8
- `8b d8' `8b d8' 88P' "Y8 88 88 88 88P' `"8a a8" `Y88
- `8a a8' `8a a8' 88 88 88 88 88 88 8b 88
- `8a8' `8a8' 88 88 88, 88 88 88 "8a, ,d88
- `8' `8' 88 88 "Y888 88 88 88 `"YbbdP"Y8
- aa, ,88
- "Y8bbdP"
- */
- /**--------------------------------------------------------------------------**\
- <summary>INI_WriteString</summary>
- <param name="INI:file">File to write to.</param>
- <param name="name[]">Data name.</param>
- <param name="data[]">Data.</param>
- <returns>
- -
- </returns>
- <remarks>
- Wrapper for INI_AddToBuffer for strings.
- </remarks>
- \**--------------------------------------------------------------------------**/
- stock INI_WriteString(INI:file, name[], data[])
- {
- P:3("INI_WriteString called: %i, \"%s\", \"%s\"", _:file, name, data);
- return INI_AddToBuffer(file, name, data);
- }
- /**--------------------------------------------------------------------------**\
- <summary>INI_WriteInt</summary>
- <param name="INI:file">File to write to.</param>
- <param name="name[]">Data name.</param>
- <param name="data">Integer data.</param>
- <returns>
- -
- </returns>
- <remarks>
- Wrapper for INI_AddToBuffer for integers. Fixed for very large numbers
- based on code by Slice from "fixes.inc" for "valstr".
- </remarks>
- \**--------------------------------------------------------------------------**/
- stock INI_WriteInt(INI:file, name[], data)
- {
- P:3("INI_WriteInt called: %i, \"%s\", %i", _:file, name, data);
- static const
- sc_szCellmin[] = !"-2147483648";
- if (data == cellmin)
- {
- return INI_AddToBuffer(file, name, sc_szCellmin);
- }
- else
- {
- return
- format(YSI_g_sINITmpBuffer, sizeof (YSI_g_sINITmpBuffer), "%d", data),
- INI_AddToBuffer(file, name, YSI_g_sINITmpBuffer);
- }
- }
- /**--------------------------------------------------------------------------**\
- <summary>INI_WriteHex</summary>
- <param name="INI:file">File to write to.</param>
- <param name="name[]">Data name.</param>
- <param name="data">Hex data.</param>
- <returns>
- -
- </returns>
- <remarks>
- Wrapper for INI_AddToBuffer for integers to be written as hex values.
- </remarks>
- \**--------------------------------------------------------------------------**/
- stock INI_WriteHex(INI:file, name[], data)
- {
- P:3("INI_WriteHex called: %i, \"%s\", %i", _:file, name, data);
- return
- format(YSI_g_sINITmpBuffer, sizeof (YSI_g_sINITmpBuffer), "0x%04x%04x", data >>> 16, data & 0xFFFF),
- INI_AddToBuffer(file, name, YSI_g_sINITmpBuffer);
- }
- /**--------------------------------------------------------------------------**\
- <summary>INI_WriteBin</summary>
- <param name="INI:file">File to write to.</param>
- <param name="name[]">Data name.</param>
- <param name="data">Binary data.</param>
- <returns>
- -
- </returns>
- <remarks>
- Wrapper for INI_AddToBuffer for integers to be written as binary values.
- </remarks>
- \**--------------------------------------------------------------------------**/
- stock INI_WriteBin(INI:file, name[], data)
- {
- P:3("INI_WriteBin called: %i, \"%s\", %i", _:file, name, data);
- if (data < 0) format(YSI_g_sINITmpBuffer, sizeof (YSI_g_sINITmpBuffer), "0b1%031b", data & 0x7FFFFFFF);
- else format(YSI_g_sINITmpBuffer, sizeof (YSI_g_sINITmpBuffer), "0b%b", data);
- return INI_AddToBuffer(file, name, YSI_g_sINITmpBuffer);
- }
- /**--------------------------------------------------------------------------**\
- <summary>INI_WriteBool</summary>
- <param name="INI:file">File to write to.</param>
- <param name="name[]">Data name.</param>
- <param name="data">Boolean data.</param>
- <returns>
- -
- </returns>
- <remarks>
- Wrapper for INI_AddToBuffer for booleans.
- </remarks>
- \**--------------------------------------------------------------------------**/
- stock INI_WriteBool(INI:file, name[], bool:data)
- {
- P:3("INI_WriteBool called: %i, \"%s\", %i", _:file, name, _:data);
- return INI_AddToBuffer(file, name, data ? ("true") : ("false"));
- }
- /**--------------------------------------------------------------------------**\
- <summary>INI_WriteFloat</summary>
- <param name="INI:file">File to write to.</param>
- <param name="name[]">Data name.</param>
- <param name="Float:data">Float data.</param>
- <param name="accuracy">number of decimal places to write.</param>
- <returns>
- -
- </returns>
- <remarks>
- Wrapper for INI_AddToBuffer for floats.
- </remarks>
- \**--------------------------------------------------------------------------**/
- stock INI_WriteFloat(INI:file, name[], Float:data, accuracy = 6)
- {
- P:3("INI_WriteFloat called: %i, \"%s\", %f, %i", _:file, name, data, accuracy);
- return
- format(YSI_g_sINITmpBuffer, sizeof (YSI_g_sINITmpBuffer), "%.*f", accuracy, data),
- INI_AddToBuffer(file, name, YSI_g_sINITmpBuffer);
- }
- /*
- 88 88 88
- 88 88 88
- 88 88 88
- 88aaaaaaaa88 ,adPPYba, ,adPPYba, 88 ,d8 ,adPPYba,
- 88""""""""88 a8" "8a a8" "8a 88 ,a8" I8[ ""
- 88 88 8b d8 8b d8 8888[ `"Y8ba,
- 88 88 "8a, ,a8" "8a, ,a8" 88`"Yba, aa ]8I
- 88 88 `"YbbdP"' `"YbbdP"' 88 `Y8a `"YbbdP"'
- */
- hook OnScriptInit()
- {
- // Set up the linked list of free tag and K/V slots.
- for (new i = 0; i != sizeof (YSI_g_sINITagBuffer) - 1; ++i)
- {
- YSI_g_sINITagBuffer[i][E_INI_TAGS_NEXT] = i + 1;
- }
- for (new i = 0; i != sizeof (YSI_g_sINIWriteBuffer) - 1; ++i)
- {
- YSI_g_sINIWriteBuffer[i][E_INI_KV_ENTRY_NEXT] = i + 1;
- }
- // Start and end value.
- YSI_g_sINITagBuffer[sizeof (YSI_g_sINITagBuffer) - 1][E_INI_TAGS_NEXT] = YSI_g_sINIWriteBuffer[sizeof (YSI_g_sINIWriteBuffer) - 1][E_INI_KV_ENTRY_NEXT] = -1,
- YSI_g_sINITagPos = YSI_g_sINIWritePos = 0;
- }
- /*
- 88 88
- 88 ,d 88
- 88 88 88
- 88 8b,dPPYba, MM88MMM ,adPPYba, 8b,dPPYba, 8b,dPPYba, ,adPPYYba, 88
- 88 88P' `"8a 88 a8P_____88 88P' "Y8 88P' `"8a "" `Y8 88
- 88 88 88 88 8PP""""""" 88 88 88 ,adPPPPP88 88
- 88 88 88 88, "8b, ,aa 88 88 88 88, ,88 88
- 88 88 88 "Y888 `"Ybbd8"' 88 88 88 `"8bbdP"Y8 88
- */
- static stock INI_GetTag(INI:file, const tag[])
- {
- new
- cur = YSI_g_sINIStartTag[file];
- while (cur != -1)
- {
- if (!strcmp(tag, YSI_g_sINITagBuffer[cur][E_INI_TAGS_NAME], true))
- {
- return cur;
- }
- cur = YSI_g_sINITagBuffer[cur][E_INI_TAGS_NEXT];
- }
- return -1;
- }
- /**--------------------------------------------------------------------------**\
- <summary>INI_FreeEntry</summary>
- <param name="slot">Slot to remove.</param>
- <returns>
- -
- </returns>
- <remarks>
-
- </remarks>
- \**--------------------------------------------------------------------------**/
- static stock INI_FreeEntry(slot)
- {
- new
- ret = YSI_g_sINIWriteBuffer[slot][E_INI_KV_ENTRY_NEXT];
- // Add this entry to the "free" list.
- return
- YSI_g_sINIWriteBuffer[slot][E_INI_KV_ENTRY_NEXT] = YSI_g_sINIWritePos,
- YSI_g_sINIWritePos = slot,
- ret;
- }
- static stock INI_DumpTag(File:buffer, curTag)
- {
- new
- curSlot = YSI_g_sINITagBuffer[curTag][E_INI_TAGS_START];
- while (0 <= curSlot < sizeof (YSI_g_sINIWriteBuffer))
- {
- fwrite(buffer, YSI_g_sINIWriteBuffer[curSlot][E_INI_KV_ENTRY_NAME]),
- fwrite(buffer, " = "),
- fwrite(buffer, YSI_g_sINIWriteBuffer[curSlot][E_INI_KV_ENTRY_TEXT]),
- fwrite(buffer, INI_NEW_LINE),
- curSlot = INI_FreeEntry(curSlot);
- }
- }
- /*stock INI_WriteArray(INI:file, const name[], data[], len)
- {
- // Write 6 bits at a time, in 3 cell chunks. It takes 16 bytes to record
- // three cells with 6 bits per byte.
- P:4("INI_WriteArray called");
- new
- dname[MAX_INI_ENTRY_NAME],
- write[Y_INI_WRITE_ARRAY_SIZE + 1],
- idx,
- wi,
- iter;
- // Write the length first just so the data exists.
- //INI_WriteInt(file, name, len);
- valstr(write, len),
- INI_AddToBuffer(file, name, write),
- write[0] = '\0';
- while (idx + 3 < len)
- {
- // Store all the data fast.
- write[wi++] = ((data[idx] & 0xFC000000) >>> 26) + '>',
- write[wi++] = ((data[idx] & 0x03F00000) >>> 20) + '>',
- write[wi++] = ((data[idx] & 0x000FC000) >>> 14) + '>',
- write[wi++] = ((data[idx] & 0x00003F00) >>> 8) + '>',
- write[wi++] = ((data[idx] & 0x000000FC) >>> 2) + '>',
- write[wi++] = (((data[idx] & 0x00000003) << 4) | ((data[idx + 1] & 0xF0000000) >>> 28)) + '>',
- ++idx,
- write[wi++] = ((data[idx] & 0x0FC00000) >>> 22) + '>',
- write[wi++] = ((data[idx] & 0x003F0000) >>> 16) + '>',
- write[wi++] = ((data[idx] & 0x0000FC00) >>> 10) + '>',
- write[wi++] = ((data[idx] & 0x000003F0) >>> 4) + '>',
- write[wi++] = (((data[idx] & 0x0000000F) << 2) | ((data[idx + 1] & 0xC0000000) >>> 30)) + '>',
- ++idx,
- write[wi++] = ((data[idx] & 0x3F000000) >>> 24) + '>',
- write[wi++] = ((data[idx] & 0x00FC0000) >>> 18) + '>',
- write[wi++] = ((data[idx] & 0x0003F000) >>> 12) + '>',
- write[wi++] = ((data[idx] & 0x00000FC0) >>> 6) + '>',
- write[wi++] = ((data[idx] & 0x0000003F) >>> 0) + '>',
- ++idx;
- if (wi == Y_INI_WRITE_ARRAY_SIZE)
- {
- format(dname, sizeof (dname), "@@%s-%d", name, iter++);
- P:5("Uvar_WriteArray: write %s = %s", dname, write);
- write[wi] = '\0',
- INI_AddToBuffer(file, dname, write),
- write[0] = '\0',
- wi = 0;
- }
- }
- // Do the straggling bytes.
- if (idx != len)
- {
- write[wi++] = ((data[idx] & 0xFC000000) >>> 26) + '>',
- write[wi++] = ((data[idx] & 0x03F00000) >>> 20) + '>',
- write[wi++] = ((data[idx] & 0x000FC000) >>> 14) + '>',
- write[wi++] = ((data[idx] & 0x00003F00) >>> 8) + '>',
- write[wi++] = ((data[idx] & 0x000000FC) >>> 2) + '>';
- if (++idx == len)
- {
- write[wi++] = ((data[idx - 1] & 0x00000003) << 4) + '>';
- }
- else
- {
- write[wi++] = (((data[idx - 1] & 0x00000003) << 4) | ((data[idx] & 0xF0000000) >>> 28)) + '>',
- write[wi++] = ((data[idx] & 0x0FC00000) >>> 22) + '>',
- write[wi++] = ((data[idx] & 0x003F0000) >>> 16) + '>',
- write[wi++] = ((data[idx] & 0x0000FC00) >>> 10) + '>',
- write[wi++] = ((data[idx] & 0x000003F0) >>> 4) + '>';
- if (++idx == len)
- {
- write[wi++] = ((data[idx - 1] & 0x0000000F) << 2) + '>';
- }
- else
- {
- write[wi++] = (((data[idx - 1] & 0x0000000F) << 2) | ((data[idx] & 0xC0000000) >>> 30)) + '>',
- write[wi++] = ((data[idx] & 0x3F000000) >>> 24) + '>',
- write[wi++] = ((data[idx] & 0x00FC0000) >>> 18) + '>',
- write[wi++] = ((data[idx] & 0x0003F000) >>> 12) + '>',
- write[wi++] = ((data[idx] & 0x00000FC0) >>> 6) + '>',
- write[wi++] = ((data[idx] & 0x0000003F) >>> 0) + '>';
- }
- }
- format(dname, sizeof (dname), "@@%s-%d", name, iter++);
- P:5("Uvar_WriteArray: write %s = %s", dname, write);
- write[wi] = '\0',
- INI_AddToBuffer(file, dname, write),
- write[0] = '\0',
- wi = 0;
- }
- return 1;
- }*/
- /**--------------------------------------------------------------------------**\
- <summary>INI_AddToBuffer</summary>
- <param name="INI:file">INI file to write to.</param>
- <param name="name[]">Data name to write.</param>
- <param name="data[]">Data to write.</param>
- <returns>
- The slot written to, or -1 on failure.
- </returns>
- <remarks>
- First checks the name doesn't already exist under the current tag header
- and if it does overwrites the current value. If not checks there's room
- in the buffer to write to and purges the buffer if not. Finally saves the
- data in the buffer for writing when required and adds the data to the
- relevant list for tag inclusion.
- </remarks>
- \**--------------------------------------------------------------------------**/
- _Y_INI_STATIC stock INI_AddToBuffer(INI:file, const key[], const value[])
- {
- P:4("INI_AddToBuffer called: %i, \"%s\", \"%s\"", _:file, key, value);
- if (INI_IsValid(file) && key[0])
- {
- // Get the current tag.
- new
- curTag = YSI_g_sINICurrentTag[file];
- if (curTag == -1) curTag = INI_SetTag(file, INI_NO_TAG);
- else
- {
- // Find if this entry already exists.
- new
- curSlot = YSI_g_sINITagBuffer[curTag][E_INI_TAGS_START];
- if (curSlot == cellmax) return -1; // Deleted tag, don't save.
- else while (curSlot != -1)
- {
- if (!strcmp(key, YSI_g_sINIWriteBuffer[curSlot][E_INI_KV_ENTRY_NAME], true))
- {
- return
- strcpy(YSI_g_sINIWriteBuffer[curSlot][E_INI_KV_ENTRY_TEXT], value, MAX_INI_ENTRY_TEXT),
- curSlot;
- }
- curSlot = YSI_g_sINIWriteBuffer[curSlot][E_INI_KV_ENTRY_NEXT];
- }
- }
- // Get a new slot.
- if (YSI_g_sINIWritePos == -1)
- {
- // Free up some space.
- if (!INI_Flush()) return -1;
- curTag = YSI_g_sINICurrentTag[file];
- }
- // Get a free slot in the system.
- new
- newSlot = YSI_g_sINIWritePos;
- YSI_g_sINIWritePos = YSI_g_sINIWriteBuffer[YSI_g_sINIWritePos][E_INI_KV_ENTRY_NEXT],
- YSI_g_sINIWriteBuffer[newSlot][E_INI_KV_ENTRY_NEXT] = YSI_g_sINITagBuffer[curTag][E_INI_TAGS_START],
- YSI_g_sINITagBuffer[curTag][E_INI_TAGS_START] = newSlot;
- // Now write to it.
- return
- strcpy(YSI_g_sINIWriteBuffer[newSlot][E_INI_KV_ENTRY_NAME], key, MAX_INI_ENTRY_NAME),
- strcpy(YSI_g_sINIWriteBuffer[newSlot][E_INI_KV_ENTRY_TEXT], value, MAX_INI_ENTRY_TEXT),
- newSlot;
- }
- return -1;
- }
- static stock INI_FreeTag(INI:file, tag)
- {
- new
- prev = -1,
- curSlot = YSI_g_sINIStartTag[file];
- while (curSlot != tag)
- {
- curSlot = YSI_g_sINITagBuffer[(prev = curSlot)][E_INI_TAGS_NEXT];
- }
- if (prev == -1) YSI_g_sINIStartTag[file] = YSI_g_sINITagBuffer[curSlot][E_INI_TAGS_NEXT];
- else YSI_g_sINITagBuffer[prev][E_INI_TAGS_NEXT] = YSI_g_sINITagBuffer[curSlot][E_INI_TAGS_NEXT];
- // Release this tag slot.
- return
- prev = YSI_g_sINITagBuffer[curSlot][E_INI_TAGS_NEXT],
- YSI_g_sINITagBuffer[curSlot][E_INI_TAGS_NEXT] = YSI_g_sINITagPos,
- YSI_g_sINITagPos = curSlot,
- prev;
- }
- /*
- I8, 8 ,8I 88 88
- `8b d8b d8' "" ,d ""
- "8, ,8"8, ,8" 88
- Y8 8P Y8 8P 8b,dPPYba, 88 MM88MMM 88 8b,dPPYba, ,adPPYb,d8
- `8b d8' `8b d8' 88P' "Y8 88 88 88 88P' `"8a a8" `Y88
- `8a a8' `8a a8' 88 88 88 88 88 88 8b 88
- `8a8' `8a8' 88 88 88, 88 88 88 "8a, ,d88
- `8' `8' 88 88 "Y888 88 88 88 `"YbbdP"Y8
- aa, ,88
- "Y8bbdP"
- */
- static stock bool:INI_Flush()
- {
- for (new INI:i = INI:0; i != INI:INI_MAX_WRITES; ++i)
- {
- if (YSI_g_sINIWriteFile[i][0])
- {
- new
- curTag = YSI_g_sINICurrentTag[i],
- tag2[MAX_INI_TAG] = "\1\0";
- if (curTag != -1) strunpack(tag2, YSI_g_sINITagBuffer[curTag][E_INI_TAGS_NAME]);
- if (!INI_WriteBuffer(i)) return false;
- if (curTag != -1) INI_SetTag(i, tag2);
- }
- }
- return true;
- }
- /**--------------------------------------------------------------------------**\
- <summary>INI_WriteBuffer</summary>
- <param name="INI:file">INI stream to write to file.</param>
- <returns>
- Success/fail.
- </returns>
- <remarks>
- Opens the required file for reading and a temp file for read/writing. Goes
- through the entire file reading all contained data. If it reaches a tag
- line ([tag_name]) it dumps any unwritten data from the last tag (if there
- was one) and starts processing the new tag. While a tag is being processed
- every line is compared against the UNWRITTEN new data for that tag in the
- buffer, if they're the same it writes the new data instead (it also writes
- any comments which were after the data in the original line back), else it
- writes the original line back.
-
- Once all the new data is written to the temp file any tags which haven't
- been processed at all (i.e. were not found in the original file) are
- written to the temp file along with all their data. The original file is
- then destroyed and reopend and all the data copied out from the temp file
- to the newly opened original file, closed and saved.
- </remarks>
- \**--------------------------------------------------------------------------**/
- static stock bool:INI_WriteBuffer(INI:file)
- {
- if (!INI_IsValid(file)) return false;
- static
- sLine[MAX_INI_LINE];
- new
- File:buffer = ftemp();
- if (!buffer) return false;
- new
- File:source = fopen(YSI_g_sINIWriteFile[file], io_read);
- if (!source) return fclose(buffer), false;
- // Start the processing. Code again copied from "INI_ParseFile".
- new
- p0s, p0e, p1s, p1e, p2s, p2e,
- curTag = INI_GetTag(file, NULL), // Get the empty tag.
- // See if this tag should be saved or not.
- bool:deleted = INI_IsDeleted(curTag);
- while (fread(source, sLine))
- {
- switch (INI_IdentifyLineType(sLine, p0s, p0e, p1s, p1e, p2s, p2e))
- {
- case e_INI_LINE_TYPE_INVALID:
- P:I("Invalid line in INI file \"%s\": %s", YSI_g_sINIWriteFile[file], sLine);
- case e_INI_LINE_TYPE_DATALESS:
- if (!deleted) fwrite(buffer, sLine);
- case e_INI_LINE_TYPE_TAG:
- {
- // Clean up the previous tag.
- if (curTag != -1)
- {
- if (!deleted) INI_DumpTag(buffer, curTag);
- // Get rid of this tag (now empty).
- INI_FreeTag(file, curTag);
- }
- // Then get the new tag to write from.
- new
- ch = sLine[p0e];
- sLine[p0e] = '\0',
- curTag = INI_GetTag(file, sLine[p0s]);
- if (!(deleted = INI_IsDeleted(curTag)))
- {
- sLine[p0e] = ch,
- fwrite(buffer, sLine);
- }
- }
- default: // e_INI_LINE_TYPE_ENTRY and e_INI_LINE_TYPE_CONT.
- {
- if (deleted) continue; // Delete the entry.
- if (curTag == -1) fwrite(buffer, sLine); // No replacement data.
- else
- {
- new
- prev = -1,
- curSlot = YSI_g_sINITagBuffer[curTag][E_INI_TAGS_START];
- p0e -= p0s;
- while (curSlot != -1)
- {
- if (!strcmp(sLine[p0s], YSI_g_sINIWriteBuffer[curSlot][E_INI_KV_ENTRY_NAME], true, p0e))
- {
- fwrite(buffer, YSI_g_sINIWriteBuffer[curSlot][E_INI_KV_ENTRY_NAME]),
- fwrite(buffer, " = "),
- fwrite(buffer, YSI_g_sINIWriteBuffer[curSlot][E_INI_KV_ENTRY_TEXT]);
- // Write the end bits.
- if (p2s != p2e) INI_WriteComments();
- else fwrite(buffer, INI_NEW_LINE);
- break;
- }
- curSlot = YSI_g_sINIWriteBuffer[(prev = curSlot)][E_INI_KV_ENTRY_NEXT];
- }
- if (curSlot == -1) fwrite(buffer, sLine); // Not replaced.
- else
- {
- // Free this now written slot.
- if (prev == -1)
- {
- if ((YSI_g_sINITagBuffer[curTag][E_INI_TAGS_START] = YSI_g_sINIWriteBuffer[curSlot][E_INI_KV_ENTRY_NEXT]) == -1)
- {
- // No items left in the tag.
- INI_FreeTag(file, curTag),
- curTag = -1;
- // Don't reset "deleted" though.
- }
- }
- else YSI_g_sINIWriteBuffer[prev][E_INI_KV_ENTRY_NEXT] = YSI_g_sINIWriteBuffer[curSlot][E_INI_KV_ENTRY_NEXT];
- YSI_g_sINIWriteBuffer[curSlot][E_INI_KV_ENTRY_NEXT] = YSI_g_sINIWritePos,
- YSI_g_sINIWritePos = curSlot;
- }
- }
- }
- }
- // Don't put any code down here (at the end of the loop).
- }
- // FIRST write out the rest of the current tag.
- if (curTag != -1)
- {
- if (!deleted) INI_DumpTag(buffer, curTag);
- INI_FreeTag(file, curTag);
- }
- // THEN do the remaining new tags.
- curTag = YSI_g_sINIStartTag[file];
- while (curTag != -1)
- {
- if (YSI_g_sINITagBuffer[curTag][E_INI_TAGS_START] != cellmax)
- {
- new
- tag[32];
- // Write the tag's name.
- strunpack(tag, YSI_g_sINITagBuffer[curTag][E_INI_TAGS_NAME]);
- fwrite(buffer, "["),
- fwrite(buffer, tag),
- fwrite(buffer, "]" INI_NEW_LINE),
- INI_DumpTag(buffer, curTag);
- }
- curTag = INI_FreeTag(file, curTag);
- }
- // Done writing, copy the results over.
- fclose(source),
- fremove(YSI_g_sINIWriteFile[file]),
- fseek(buffer);
- if (!(source = fopen(YSI_g_sINIWriteFile[file], io_write))) return fclose(buffer), false;
- // Copy the buffer over.
- while (fread(buffer, sLine)) fwrite(source, sLine);
- return
- fclose(buffer),
- fclose(source),
- true;
- }
|