This system automates configuration files.
It's very easy to use, it's overhead is low, and you can have upto ten files on the go at any time. (It's v.easy to extend beyond ten).
You can use config files for all sorts of things; INIs, highscores, inventory saves, entity variables, whatever.
If you want easy file handing this is for you.
REMSTART
INI
An automated multi-configuration file system.
by viberunner
Copyright: Public Domain. Have as your own. Enjoy.
BY THE SAME AUTHOR
O-Cycle, object-cycling system
KeyTap, keypress tamer/counter
This is a configuration file system.
This system automates all manner of configuration files;
loading and saving them; getting and updating values;
and removing values.
This system works for up to ten files; though you'll see
it's easy to extend it beyond ten.
The development emphasis was upon robustness; stability
and functionality is bred from from elegant functions.
I'm rather pleased with the outcome of this project.
Here is an example of a highscore system, in it's entirity:
` Let's have plenty of information for the highscore table
TYPE Scoreboard_TYPE
score AS INTEGER
name AS STRING
rank AS STRING
ENDTYPE
number_of_scores = 9
DIM hiscores(number_of_scores) AS Scoreboard_TYPE
` Doesn't matter if the file exists or not.
INI_LOAD("Highscore Table.txt")
` Interrogate, to load the hiscore array
FOR i = 0 TO number_of_scores
label$ = "Player " + STR$(i)
hiscores(i).name = INI_GET_STRING(label$, "New Player Slot")
label$ = "Rank " + STR$(i)
hiscores(i).rank = INI_GET_STRING(label$, "Harmless")
label$ = "Score " + STR$(i)
hiscores(i).score = INI_GET_NUMBER(label$, 0)
NEXT i
` The hiscore array is now loaded with scores. If the file
` did not exist the hiscore array is loaded with zeroes and with
` names and ranks of "New Player" and "Harmless". They are default
` values if the tags are not found.
` GAME CODE ** WE'LL MIMICK WITH RND() TO INCREASE THE SCORES, ETC
FOR i = 0 TO number_of_scores
INC hiscores(i).score,RND(999)
IF i = 0 THEN hiscores(i).name = "viberunner" : INC hiscores(i).score,10000
IF hiscores(i).score > 250 THEN hiscores(i).rank = "Mostly Harmless"
IF hiscores(i).score > 1000 THEN hiscores(i).rank = "Dangerous"
IF hiscores(i).score > 2000 THEN hiscores(i).rank = "Deadly"
IF hiscores(i).score > 9999 THEN hiscores(i).rank = "ELITE"
NEXT i
` SORT THE HIGH SCORES?
` Sorting the array is an extended manual task. If you are interested and
` don't know about it, search "Bubble Sort" on Wikipedia.
` However if you have the *most* *excellent* Matrix1Array.dll plug-in
` then you can use it to sort the table, just use:
` SORT ARRAY hiscores(0)
` The score integer is the first part of the UDT, which this sorts on.
` You can get the dll by examining the DBP forums, or by emailing me
` and I'll help. All the Matrix1 dll utilities are well worth getting.
` Replace the hiscore array into the INI file system.
FOR i = 0 TO number_of_scores
label$ = "Player " + STR$(i)
INI_CHANGE_STRING(label$, hiscores(i).name)
label$ = "Rank " + STR$(i)
INI_CHANGE_STRING(label$, hiscores(i).rank)
label$ = "Score " + STR$(i)
INI_CHANGE_NUMBER(label$, hiscores(i).score)
NEXT i
` Save the file
INI_SAVE("Highscore Table.txt")
And that's it. A working 10-person highscore table with names, scores, and ranks;
ready for use in your game!!!!!
If you run that code, the file has these sorts of values:
[player 0]=viberunner
[rank 0]=ELITE
[score 0]=10765
[player 1]=New Player Slot
[rank 1]=Mostly Harmless
[score 1]=136
Try running that program first without a hiscore table, then run it again
when one exists, and re-run it. Examine the file. Now change some of the names
and other variables. Note you can remove some of the tags, and sort the array
in any crazy order; and it all seems to work pretty good. Cool huh?
You can use this system of creating tags to create a similar effect
to some scripting languages, e.g. [soldier ammo], [red dragon health max], etc.
HOW IT WORKS
The system uses arrays, global and logal, to load and save files;
the system interrogates, modifies, and swithces, those arrays.
These arrays are accessed through functions.
ARRAYS, so avoid the same anywhere in your code
INI() active system
INID() delete tags
INIW() write file
INIF() write control
INIB() storage control
INI0() storage slot
INI1() storage slot
INI2() storage slot
INI3() storage slot
INI4() storage slot
INI5() storage slot
INI6() storage slot
INI7() storage slot
INI8() storage slot
INI9() storage slot
The storage arrays are only created as they are required.
REM ** START
INI_LOAD()
This function MUST be called before any of the
other functions.
Tries to load an INI file. If it exists it is
placed into INI() array, if it does not exist
the INI() array is created empty.
This function does not leave any files open.
REM ** USE
INI_GET_x()
INI_CHANGE_x()
Where 'x' could be STRING, NUMBER, or FLOAT.
Various commands to get information from the INI()
array; and commands for changing information in
the array, including adding it.
There are "safe" versions for the numerics which
cap minimums and maximums.
These commands address the INI() arrays, not files.
REM ** FINISH
INI_SAVE()
Saves the INI array. Over-writes any existing
file to save whatever is in the INI() array.
It drops blank (empty) elements, and drops
all duplicate tags. (The first occurrence of a
tag is written to the file, all others dropped.)
REM ** MULTIPLE FILES
INI_FREEZE()
INI_THAW()
INI_BURN()
These freeze the currently-loaded INI array, and
thaw a frozen INI array into live use. This is a
swapping mechanism permitting up to 10 files to be used.
Use burn to empty a slot.
REM ** DELETE TAGS
INI_DELETE_TAG(tag)
INI_UNDELETE()
Tags that will not be saved.
The list of Tags to exclude does not survive a Load.
Call Undelete() to clear it out if you need to, after
an Undelete all the Tags saved in Delete_Tag will be
cleared.
REM ** TAG VALIDATION
INI_TAG_VALIDATE(tag)
This will strip = and [ ] characters from a string,
making sure it is acceptable to use as a label.
This is handy for programs where users can enter labels.
SOME INFO
(1) An INI file has TWO line types; DATA and TEXT.
(2) DATA line. Has a LABEL, an EQUALS, and a VALUE
The LABEL is a TAG surrounded by Square Brackets, [ }
The TAG is text of absolutely any letter, number, or special
character, with the exception of either Square Bracket
and with the additional exeption of =.
Some validation exists on this, but AVOID square brackets
and equals as labels.
String VALUEs may include any number of equals and square brackets.
The VALUE is: 'all the characters after the first EQUALs after the LABEL'.
The VALUE may be null.
[screen width]=1024
Label: [screen width]
Tag: screen width
Value: 1024
You only ever care about Tags and Values. You don't use Labels.
(3) The VALUE can be Integer (double), String, or Float (double float), or blank.
Floats are currently unreliable. For more info see section below.
(4) A TEXT line is any line that is not a DATA line.
// A Comment Line
/* Another Comment Line */
REM More Comments
` Yet Another Comment Line
! Yes a comment.
And this is also commentary, you don't need a silly character to begin!
(5) Duplicate (subsequent) TAGs get dropped.
(6) You can type Tag parameters in functions in any case; they are
converted to, used, and stored in, lowercase.
(7) Use the FREEZE/THAW system to juggle up to ten active files.
The active file is the one just Loaded, or Thawed; and the active
file is the one all the other functions work on. At any time you
can Freeze the currently active file into a storage slot. Once
Frozen you can Thaw a slot at any time.
If you wish to unload a Freeze slot you can Burn it.
(8) You can use the DELETE system to drop Tags.
(9) This program uses no GLOBAL files, but check any GLOBAL
variables you have are not used in the functions.
FLOATS
There is imprecision with floating numbers, due to inaccurate
conversion between strings and floats. This will be fixed in
due course, but that will take some effort.
It might still be of use to store 3D co-ordinates for transitional
play entities, though you won't want to make a level editor or
currency-conversion suite with this system just yet!
STRINGS and INTEGERS are reliable. Actually the system takes and
uses DOUBLE INTEGERS. You can use either.
FUNCTIONS:
` LOAD/SAVE FILE
success boolean = INI_LOAD(filename)
success boolean = INI_SAVE(filename)
` RETRIEVE A VALUE
string$ = INI_GET_STRING(tag, default$)
number = INI_GET_NUMBER(tag, default)
number = INI_GET_NUMBER_CAP(tag, default)
float# = INI_GET_FLOAT(tag, default#)
` RETRIEVE A VALUE SAFELY
number = INI_GET_NUMBER_SAFE(tag, default, min, max)
float# = INI_GET_FLOAT_SAFE(tag, default#, min#, max#)
The returned value will not be beneath the min or above the max.
This is handy for checking against someon putting out-of-range
values into a field.
Example, to get MUSIC VOLUME, a percentage value.
volume = INI_GET_NUMBER_SAFE("music volume",75,0,100)
[music volume]=-1 gives 0
[music volume]=150 gives 100
If the tag is not found at all, gives 75
` UPDATE A VALUE
string$ = INI_CHANGE_STRING(tag, value$)
number = INI_CHANGE_NUMBER(tag, value)
float# = INI_CHANGE_FLOAT(tag, value#)
` FIND IF A TAG EXISTS
success boolean = INI_TEST_TAG(tag)
Returns 1 if a tag is in the array, else 0.
` DELETE TAGS
INI_DELETE_TAG(tag)
INI_UNDELETE()
` VALIDATE TAG
valid_tag$ = INI_TAG_VALIDATE(tag)
` MULTIPLE FILES
success boolean = INI_FREEZE(number)
success boolean = INI_THAW(number)
success boolean = INI_BURN(number)
Number is a value from 0 to 9
A Frozen file cannot be interrogated, updated,
or saved until it has been Thawed. You can
Burn any Frozen slot, emptying it.
The "active" INI file is the one most recently
Loaded or Thawed.
The success boolean is standard 1=success, 0=fail
` ** TECH FUNCTIONS ** DO NOT CALL DIRECTLY **
INI_LABEL(), returns the label of an index
INI_DATA(), returns the data of an index
INI_MAKE_LABEL(), returns the lable of a tag
INI_CLEAN_LABEL(), cleans = from labels
INI_FIND_INDEX(), finds the index of a tag
INI_ADD_STRING(), adds a string
INI_ADD_NUMBER(), adds an double integer
INI_ADD_FLOAT(), adds a double float
REMEND
` ##### DEMO PROGRAM START ######
` ##### DEMO PROGRAM START ######
` ##### DEMO PROGRAM START ######
REMSTART
EXAMPLE:
File: Film.INI
// FAVOURITE FILM
[film name]=star wars
[jedi]=Luke
[==d=e=a=t=h=== ===s=t=a=r===]=NOW=Destroyed
[chewy chess wins]=2001
[episode]=4
[episode]=99
Watch the 'episode' field, and note the 'death star' too.
REMEND
TIME AS DOUBLE FLOAT = 0.0
TIME = TIMER()
` Explicit definitions!
df# AS DOUBLE FLOAT = 0.0
success AS BOOLEAN = 0
` LOAD - initialise the system
success = INI_LOAD("Film.INI")
IF success = 1
PRINT "LOAD: File found. File values used."
ELSE
PRINT "LOAD: File NOT found. Don't Panic! Default values used."
ENDIF
` GET - can be done any time after a Load;
` first parameter is tag, second parameter is is default value
` Note the EQUALs inside the sandcrawler fuel text will be stripped
df# = INI_GET_FLOAT("sandcrawler fuel=",6.6)
episode = INI_GET_NUMBER("Episode",1)
film$ = INI_GET_STRING("FILM NAME","")
sith$ = INI_GET_STRING("sith lord","Darth Vader")
` CHANGES - can be done any time after a Load
INC episode
df# = 0.000000222
INI_CHANGE_FLOAT("space",df#)
INI_CHANGE_NUMBER("episode",episode)
INI_CHANGE_STRING("film name","The Empire Strikes Back!")
INI_CHANGE_STRING("jedi","Yoda")
INI_CHANGE_STRING("c3p0","GOLD")
INI_CHANGE_STRING("lightsaber","blue")
INI_CHANGE_STRING("lightsaber","green")
` Demo of Sanity Check
` Params are tag, default, min, max
chewy_wins = INI_GET_NUMBER_SAFE("chewy chess wins",2,0,9)
INC chewy_wins
INI_CHANGE_NUMBER("chewy chess wins",chewy_wins)
` Example of testing a tag's existence
IF INI_TEST_TAG("boba fett") = 0
INI_CHANGE_STRING("boba fett","Wasn't here when we arrived.")
ELSE
INI_CHANGE_STRING("boba fett","Was waiting for us.")
ENDIF
REM **
` You can use this testing to avoid writing new tags,
` remembering GET also adds tags that were not found.
IF INI_TEST_TAG("x-wing") = 1
returned_string$ = INI_GET_STRING("x-wing", "")
returned_string$ = returned_string$ + "Tie killed. "
ENDIF
IF INI_TEST_TAG("x-wing") = 1
INI_CHANGE_STRING("x-wing", returned_string$)
ENDIF
` This prevents [x-wing] from being added if it did not already exist.
REM **
` SAVE - save active file
INI_SAVE("Film 2.INI")
` FREEZE SYSTEM
` Freeze current contents (a modified Film.INI) into slot zero,
` this can be done before or after (irrespective of) a Save.
INI_FREEZE(0)
` Lets load a new file, and set something; then Freeze it in slot one.
INI_LOAD("Settings.INI")
my_speed = INI_GET_NUMBER("Speed",0)
INI_CHANGE_NUMBER("speed",my_speed + RND(9))
INI_SAVE("Settings 2.INI")
INI_FREEZE(1)
` Let's Thaw out slot zero; make an addition and save.
INI_THAW(0)
` ** TAG DELETE EXAMPLE!
` ** we drop the golden droid from this save, bye threepio! **
INI_DELETE_TAG("c3p0")
INI_CHANGE_STRING("jabba slave","third worst job on tattooine")
INI_SAVE("Film 3.INI")
` Thaw the Settings slot.
INI_THAW(1)
` Burn the Film slot.
INI_BURN(0)
` Try to Thaw the Film slot. This should fail because it was burnt.
success = INI_THAW(0)
IF success = 1
PRINT "BURN TEST: Not expecting this."
ELSE
PRINT "BURN TEST: Expecting this."
ENDIF
` Try to Thaw slot 9. This slot was never Frozen so this should fail.
INI_THAW(9)
` The last successful Load/Thaw should be Settings.
my_speed = INI_GET_NUMBER("Speed",0)
` Validate Tag
` This happens if users are give access to entering Labels, so validiate it.
my_tag$ = "[BIT = faster]"
my_tag$ = INI_TAG_VALIDATE(my_tag$)
INI_CHANGE_NUMBER(my_tag$, my_speed + my_speed)
INI_SAVE("Settings 3.INI")
TIME = (TIMER() - TIME) / 1000.0
PRINT
PRINT "Several files opened, read, changed, saved, in: ", TIME, " seconds."
WAIT KEY
END
REMSTART
Examine the 'episode' field:
if "Film.INI" existed, the tag taken from the original INI and incremented (4 to 5)
if "Film.INI" did not exist, the default (1), was taken and incremented, to 2
The comment line (//FAV..) and 'death star' tag was copied. Note the Death Star drops
the = occurances from the label; but not from the value.
Note the effect of the DELETE_TAG function on poor threepio.
File: Film 2.INI
If "Film.INI" existed:
// FAVOURITE FILM
[film name]=The Empire Strikes Back!
[jedi]=Yoda
[death star]=NOW=Destroyed
[chewy chess wins]=10
[episode]=5
[sandcrawler fuel]=6.599999904632568
[sith lord]=Darth Vader
[space]=2.22e-007
[c3p0]=GOLD
[lightsaber]=green
[boba fett]=Wasn't here when we arrived.
If "Film.INI" did not exist:
[sandcrawler fuel]=6.599999904632568
[episode]=2
[film name]=The Empire Strikes Back!
[sith lord]=Darth Vader
[space]=2.22e-007
[jedi]=Yoda
[c3p0]=GOLD
[lightsaber]=green
[chewy chess wins]=3
[boba fett]=Wasn't here when we arrived.
File: Film 3.INI
If "Film.INI" existed:
// FAVOURITE FILM
[film name]=The Empire Strikes Back!
[jedi]=Yoda
[death star]=NOW=Destroyed
[chewy chess wins]=10
[episode]=5
[sandcrawler fuel]=6.599999904632568
[sith lord]=Darth Vader
[space]=2.22e-007
[lightsaber]=green
[boba fett]=Wasn't here when we arrived.
[jabba slave]=third worst job on tattooine
If "Film.INI" did not exist:
[sandcrawler fuel]=6.599999904632568
[episode]=2
[film name]=The Empire Strikes Back!
[sith lord]=Darth Vader
[space]=2.22e-007
[jedi]=Yoda
[lightsaber]=green
[chewy chess wins]=3
[boba fett]=Wasn't here when we arrived.
[jabba slave]=third worst job on tattooine
File: Settings 2.INI, speed is random, bit faster is double it
[speed]=6
File: Settings 3.INI
[speed]=6
[bit faster]=12
REMEND
` ##### DEMO PROGRAM END ######
` ##### DEMO PROGRAM END ######
` ##### DEMO PROGRAM END ######
` ## ##### ##### ##### ##### ##### ##
` ## ##
` ## INI FUNCTIONS ##
` ## ##
` ## ##### ##### ##### ##### ##### ##
` ##
` ## INTERROGATE INI VALUES
` ##
` Returns STRING from system
FUNCTION INI_GET_STRING(tag$, value$)
i = INI_FIND_INDEX(tag$)
` Not found
IF i < 0
` Add a default
INI_ADD_STRING(tag$,value$)
ELSE
` Found, return
value$ = INI_DATA(i)
ENDIF
ENDFUNCTION value$
` Returns NUMBER from system
FUNCTION INI_GET_NUMBER(tag$, value AS DOUBLE INTEGER)
i = INI_FIND_INDEX(tag$)
` Not found
IF i < 0
` Add a default
INI_ADD_NUMBER(tag$,value)
ELSE
` Found, return
value = VAL(INI_DATA(i))
ENDIF
ENDFUNCTION value
` Returns FLOAT from system
FUNCTION INI_GET_FLOAT(tag$, value# AS DOUBLE FLOAT)
i = INI_FIND_INDEX(tag$)
` Not found
IF i < 0
` Add a default
INI_ADD_FLOAT(tag$,value#)
ELSE
` Found, return
value# = VAL(INI_DATA(i))
ENDIF
ENDFUNCTION value#
` Returns NUMBER from system, with safety caps
FUNCTION INI_GET_NUMBER_SAFE(tag$, value AS DOUBLE INTEGER, value_min AS DOUBLE INTEGER, value_max AS DOUBLE INTEGER)
i = INI_FIND_INDEX(tag$)
` Not found
IF i < 0
` Add a default
INI_ADD_NUMBER(tag$,value)
ELSE
` Found, return
value = VAL(INI_DATA(i))
ENDIF
` Safety Cap
IF value < value_min
value = value_min
ENDIF
IF value > value_max
value = value_max
ENDIF
ENDFUNCTION value
` Returns FLOAT from system, with safety caps
FUNCTION INI_GET_FLOAT_SAFE(tag$, value# AS DOUBLE FLOAT, value_min# AS DOUBLE FLOAT, value_max# AS DOUBLE FLOAT)
i = INI_FIND_INDEX(tag$)
` Not found
IF i < 0
` Add a default
INI_ADD_FLOAT(tag$,value#)
ELSE
` Found, return
value# = VAL(INI_DATA(i))
ENDIF
` Safety Cap
IF value# < value_min#
value# = value_min#
ENDIF
IF value# > value_max#
value# = value_max#
ENDIF
ENDFUNCTION value#
` ##
` ## MODIFY INI VALUES
` ##
FUNCTION INI_CHANGE_STRING(tag$, value$)
label$ = INI_MAKE_LABEL(tag$)
i = INI_FIND_INDEX(tag$)
` Not found
IF i < 0
` Add a default
INI_ADD_STRING(tag$,value$)
ELSE
` Found, change
INI(i) = label$ + "=" + value$
ENDIF
ENDFUNCTION
FUNCTION INI_CHANGE_NUMBER(tag$, value AS DOUBLE INTEGER)
label$ = INI_MAKE_LABEL(tag$)
i = INI_FIND_INDEX(tag$)
` Not found
IF i < 0
` Add a default
INI_ADD_NUMBER(tag$,value)
ELSE
` Found, change
INI(i) = label$ + "=" + STR$(value)
ENDIF
ENDFUNCTION
FUNCTION INI_CHANGE_FLOAT(tag$, value# AS DOUBLE FLOAT)
label$ = INI_MAKE_LABEL(tag$)
i = INI_FIND_INDEX(tag$)
` Not found
IF i < 0
` Add a default
INI_ADD_FLOAT(tag$,value#)
ELSE
` Found, change
INI(i) = label$ + "=" + STR$(value#)
ENDIF
ENDFUNCTION
` ##
` ## SUPPLIMENT INI VALUES
` ##
FUNCTION INI_ADD_STRING(tag$, value$)
label$ = INI_MAKE_LABEL(tag$)
` Extend and populate the main array
c = ARRAY COUNT(INI(0))
INC c
GLOBAL DIM INI(c) AS STRING
INI(c) = label$ + "=" + value$
ENDFUNCTION
FUNCTION INI_ADD_NUMBER(tag$, value AS DOUBLE INTEGER)
` Convert and call String-Add function
value$ = STR$(value)
INI_ADD_STRING(tag$,value$)
ENDFUNCTION
FUNCTION INI_ADD_FLOAT(tag$, value# AS DOUBLE FLOAT)
` Convert and call String-Add function
value$ = STR$(value#)
INI_ADD_STRING(tag$,value$)
ENDFUNCTION
` ##
` ## ASSESS INI
` ##
` ** TEST-TAG IS THE ONLY USER-FACING
` ** FUNCTION IN THE 'ACCESS INI' SECTION
` RETURNS: if tag exists, 1 = yes, 0 = no
FUNCTION INI_TEST_TAG(tag$)
label$ = INI_MAKE_LABEL(tag$)
FOR i = 0 TO ARRAY COUNT(INI(0))
search_label$ = INI_LABEL(i)
IF search_label$ = label$
` Found
EXITFUNCTION 1
ENDIF
NEXT i
` Not Found
ENDFUNCTION 0
` RETURNS: index of a tag
FUNCTION INI_FIND_INDEX(tag$)
label$ = INI_MAKE_LABEL(tag$)
FOR i = 0 TO ARRAY COUNT(INI(0))
search_label$ = INI_LABEL(i)
IF search_label$ = label$
` Found
EXITFUNCTION i
ENDIF
NEXT i
` Not Found
ENDFUNCTION -1
` RETURNS: label, lowercase; plus square brackets
FUNCTION INI_LABEL(i AS DWORD)
IF i > ARRAY COUNT(INI(0))
EXITFUNCTION ""
ENDIF
` Load the string to be checked
string$ = INI(i)
return$ = ""
FOR c = 1 TO LEN(string$)
c$ = MID$(string$,c)
IF c$ = "="
return$ = LOWER$(return$)
EXITFUNCTION return$
ENDIF
return$ = return$ + c$
NEXT c
ENDFUNCTION ""
` RETURNS: label
FUNCTION INI_MAKE_LABEL(tag$)
` Remove any occurance of EQUALs from the tag.
FOR c = 1 TO LEN(tag$)
c$ = MID$(tag$,c)
IF c$ <> "="
clean_tag$ = clean_tag$ + c$
ENDIF
NEXT c
` Construct the Label from the equals-cleased Tag
label$ = "[" + LOWER$(clean_tag$) + "]"
ENDFUNCTION label$
` RETURNS: data, in string format
FUNCTION INI_DATA(i AS DWORD)
IF i > ARRAY COUNT(INI(0))
EXITFUNCTION ""
ENDIF
` Load the string to be checked
string$ = INI(i)
return$ = ""
left_found AS BOOLEAN = 0
right_found AS BOOLEAN = 0
started AS BOOLEAN = 0
` "started"
` happens after a '[' then a ']' then the first char after the '='
FOR c = 1 TO LEN(string$)
c$ = MID$(string$,c)
` Valid Tag and = found, hereafter is Value
IF started = 1
return$ = return$ + c$
ENDIF
` Found mode not started, search of LABEL identifiers
IF started = 0
IF left_found = 0
IF c$ = "["
left_found = 1
ENDIF
ENDIF
IF right_found = 0 AND left_found = 1
IF c$ = "]"
right_found = 1
ENDIF
ENDIF
IF left_found = 1 AND right_found = 1
IF c$ = "="
started = 1
ENDIF
ENDIF
ENDIF
NEXT c
ENDFUNCTION return$
` RETURNS: input with EQUALs stripped from LABELs
FUNCTION INI_CLEAN_LABEL(string$)
left_found AS BOOLEAN = 0
right_found AS BOOLEAN = 0
started AS BOOLEAN = 0
FOR c = 1 TO LEN(string$)
c$ = MID$(string$,c)
` Valid Tag and = found, hereafter is Value
IF started = 1
` Started mode - always add the character
return$ = return$ + c$
ENDIF
` Found mode not started, search of LABEL identifiers
IF started = 0
IF left_found = 0
IF c$ = "["
left_found = 1
ENDIF
ENDIF
IF right_found = 0 AND left_found = 1
IF c$ = "]"
right_found = 1
ENDIF
ENDIF
IF left_found = 1 AND right_found = 1
` This = is valid, include it and start started mode.
IF c$ = "="
started = 1
return$ = return$ + c$
ENDIF
ENDIF
` Include any character except =
IF c$ <> "="
return$ = return$ + c$
ENDIF
ENDIF
NEXT c
` Only use the modified string if it was a valid label
IF started = 1
string$ = return$
ENDIF
ENDFUNCTION string$
` ##
` ## DELETE TAGS
` ##
FUNCTION INI_DELETE_TAG(tag$ AS STRING)
i = INI_FIND_INDEX(tag$)
` If tag found, add label
IF i > -1
label$ = INI_LABEL(i)
d = ARRAY COUNT(INID(0))
INC d
GLOBAL DIM INID(d) AS STRING
INID(d) = label$
ENDIF
ENDFUNCTION
FUNCTION INI_UNDELETE()
UNDIM INID(0)
GLOBAL DIM INID(0) AS STRING
ENDFUNCTION
` ##
` ## VALIDATE TAG
` ##
` RETURNS Valid Tag
FUNCTION INI_TAG_VALIDATE(tag$ AS STRING)
IF tag$ = ""
EXITFUNCTION ""
ENDIF
FOR c = 1 TO LEN(tag$)
c$ = MID$(tag$,c)
IF (c$ <> "=") AND (c$ <> "[") AND (c$ <> "]")
valid_tag$ = valid_tag$ + c$
ENDIF
NEXT c
valid_tag$ = LOWER$(valid_tag$)
ENDFUNCTION valid_tag$
` ##
` ## CLEVER CRYOGENICS
` ##
FUNCTION INI_FREEZE(n AS DWORD)
max_frozen_slots = 9
IF n > max_frozen_slots
` Fail
EXITFUNCTION 0
ENDIF
` Probe array virginity
IF ARRAY COUNT(INIB(0))=0
GLOBAL DIM INIB(max_frozen_slots) AS BOOLEAN
ENDIF
` Deposit in the correct slot
INIB(n) = 1
` Size of array to save
c = ARRAY COUNT(INI(0))
` Freeze the Live system in a slot
SELECT n
CASE 0
UNDIM INI0(0)
GLOBAL DIM INI0(C) AS STRING
FOR i = 0 TO C : INI0(i) = INI(i) : NEXT i
ENDCASE
CASE 1
UNDIM INI1(0)
GLOBAL DIM INI1(C) AS STRING
FOR i = 0 TO C : INI1(i) = INI(i) : NEXT i
ENDCASE
CASE 2
UNDIM INI2(0)
GLOBAL DIM INI2(C) AS STRING
FOR i = 0 TO C : INI2(i) = INI(i) : NEXT i
ENDCASE
CASE 3
UNDIM INI3(0)
GLOBAL DIM INI3(C) AS STRING
FOR i = 0 TO C : INI3(i) = INI(i) : NEXT i
ENDCASE
CASE 4
UNDIM INI4(0)
GLOBAL DIM INI4(C) AS STRING
FOR i = 0 TO C : INI4(i) = INI(i) : NEXT i
ENDCASE
CASE 5
UNDIM INI5(0)
GLOBAL DIM INI5(C) AS STRING
FOR i = 0 TO C : INI5(i) = INI(i) : NEXT i
ENDCASE
CASE 6
UNDIM INI6(0)
GLOBAL DIM INI6(C) AS STRING
FOR i = 0 TO C : INI6(i) = INI(i) : NEXT i
ENDCASE
CASE 7
UNDIM INI7(0)
GLOBAL DIM INI7(C) AS STRING
FOR i = 0 TO C : INI7(i) = INI(i) : NEXT i
ENDCASE
CASE 8
UNDIM INI8(0)
GLOBAL DIM INI8(C) AS STRING
FOR i = 0 TO C : INI8(i) = INI(i) : NEXT i
ENDCASE
CASE 9
UNDIM INI9(0)
GLOBAL DIM INI9(C) AS STRING
FOR i = 0 TO C : INI9(i) = INI(i) : NEXT i
ENDCASE
ENDSELECT
` Success
ENDFUNCTION 1
FUNCTION INI_THAW(n AS DWORD)
max_frozen_slots = 9
IF n > max_frozen_slots
` Fail
EXITFUNCTION 0
ENDIF
` Probe array virginity
IF ARRAY COUNT(INIB(0))=0
GLOBAL DIM INIB(max_frozen_slots) AS BOOLEAN
ENDIF
` Fail if nothing deposited in that slot
IF INIB(n) = 0
EXITFUNCTION 0
ENDIF
` Move a Frozen slot to the Live system
SELECT n
CASE 0
c = ARRAY COUNT(INI0(0))
GLOBAL DIM INI(C) AS STRING
FOR i = 0 TO C : INI(i) = INI0(i) : NEXT i
ENDCASE
CASE 1
c = ARRAY COUNT(INI1(0))
GLOBAL DIM INI(C) AS STRING
FOR i = 0 TO C : INI(i) = INI1(i) : NEXT i
ENDCASE
CASE 2
c = ARRAY COUNT(INI2(0))
GLOBAL DIM INI(C) AS STRING
FOR i = 0 TO C : INI(i) = INI2(i) : NEXT i
ENDCASE
CASE 3
c = ARRAY COUNT(INI3(0))
GLOBAL DIM INI(C) AS STRING
FOR i = 0 TO C : INI(i) = INI3(i) : NEXT i
ENDCASE
CASE 4
c = ARRAY COUNT(INI4(0))
GLOBAL DIM INI(C) AS STRING
FOR i = 0 TO C : INI(i) = INI4(i) : NEXT i
ENDCASE
CASE 5
c = ARRAY COUNT(INI5(0))
GLOBAL DIM INI(C) AS STRING
FOR i = 0 TO C : INI(i) = INI5(i) : NEXT i
ENDCASE
CASE 6
c = ARRAY COUNT(INI6(0))
GLOBAL DIM INI(C) AS STRING
FOR i = 0 TO C : INI(i) = INI6(i) : NEXT i
ENDCASE
CASE 7
c = ARRAY COUNT(INI7(0))
GLOBAL DIM INI(C) AS STRING
FOR i = 0 TO C : INI(i) = INI7(i) : NEXT i
ENDCASE
CASE 8
c = ARRAY COUNT(INI8(0))
GLOBAL DIM INI(C) AS STRING
FOR i = 0 TO C : INI(i) = INI8(i) : NEXT i
ENDCASE
CASE 9
c = ARRAY COUNT(INI9(0))
GLOBAL DIM INI(C) AS STRING
FOR i = 0 TO C : INI(i) = INI9(i) : NEXT i
ENDCASE
ENDSELECT
` Success
ENDFUNCTION 1
FUNCTION INI_BURN(n AS DWORD)
max_frozen_slots = 9
IF n > max_frozen_slots
` Fail
EXITFUNCTION 0
ENDIF
` Probe array virginity
IF ARRAY COUNT(INIB(0))=0
EXITFUNCTION 0
ENDIF
` Fail if nothing deposited in that slot
IF INIB(n) = 0
EXITFUNCTION 0
ELSE
` Slot found, erase control index.
INIB(n) = 0
ENDIF
` Burn slot!
SELECT n
CASE 0 : UNDIM INI0(0) : ENDCASE
CASE 1 : UNDIM INI1(0) : ENDCASE
CASE 2 : UNDIM INI2(0) : ENDCASE
CASE 3 : UNDIM INI3(0) : ENDCASE
CASE 4 : UNDIM INI4(0) : ENDCASE
CASE 5 : UNDIM INI5(0) : ENDCASE
CASE 6 : UNDIM INI6(0) : ENDCASE
CASE 7 : UNDIM INI7(0) : ENDCASE
CASE 8 : UNDIM INI8(0) : ENDCASE
CASE 9 : UNDIM INI9(0) : ENDCASE
ENDSELECT
` Success
ENDFUNCTION 1
` ##
` ## LOAD INI FILE
` ##
FUNCTION INI_LOAD(f$ AS STRING)
` New INI file
UNDIM INI(0)
GLOBAL DIM INI(0) AS STRING
` Clear Delete file
INI_UNDELETE()
` File not Found
IF FILE EXIST(f$) = 0
EXITFUNCTION 0
ENDIF
` Find free file id
REPEAT
INC n
IF n = 33
EXITFUNCTION 0
ENDIF
UNTIL FILE OPEN(n) = 0
` Start File
OPEN TO READ n,f$
` Check File Status
IF FILE OPEN(n) = 0 OR FILE END(n) = 1
EXITFUNCTION 0
ENDIF
` Count number of lines
WHILE FILE END(n) = 0
READ STRING n,s$
INC C
ENDWHILE
` To keep array/float counter consistent,
` (arrays count from element 0, we count from element one)
DEC C
` Close File
CLOSE FILE n
` Create and populate INI array
GLOBAL DIM INI(C) AS STRING
LOAD ARRAY f$,INI(0)
FOR i = 0 TO C
INI(i) = INI_CLEAN_LABEL(INI(i))
NEXT i
` Success
ENDFUNCTION 1
` ##
` ## SAVE INI FILE
` ##
FUNCTION INI_SAVE(f$ AS STRING)
` Clear file if needed
IF FILE EXIST(f$) = 1
DELETE FILE f$
ENDIF
` Found is used for duplication-detection
LOCAL found AS BOOLEAN = 0
` Load the requested Tag Deletions into the
` ini-found array. The found array is also used
` during duplicate-tag checking.
FOR i = 0 TO ARRAY COUNT(INID(0))
IF INID(i) <> ""
d = ARRAY COUNT(INIF(0))
INC d
LOCAL DIM INIF(d) AS STRING
INIF(d) = INID(i)
ENDIF
NEXT i
` Index of INIW array
c = 0
` Go through INI array
FOR i = 0 TO ARRAY COUNT(INI(0))
` Find the Label of this line
label$ = INI_LABEL(i)
` Search for duplicate tags
found = 0
FOR j = 0 TO ARRAY COUNT(INIF(0))
` Empty tags are comment lines, do not drop them.
IF label$ <> ""
` Test the found array Tag
IF INIF(j) = label$
found = 1
ENDIF
ENDIF
NEXT j
` We process only unfound tags
IF found = 0
` Put the Tag in the found array, thus any further
` occurances of the same Tag get dropped.
d = ARRAY COUNT(INIF(0))
INC d
LOCAL DIM INIF(d) AS STRING
INIF(d) = label$
` Put the INI array line into the Write array
IF LEN(INI(i)) > 0
LOCAL DIM INIW(c) AS STRING
INIW(c) = INI_CLEAN_LABEL(INI(i))
INC c
ENDIF
ENDIF
NEXT i
` Save Write Array
SAVE ARRAY f$,INIW(0)
UNDIM INIF(0)
UNDIM INIW(0)
` Success
ENDFUNCTION 1
` ### END OF FUNCTIONS
Please leave feedback.