Need help with reading INI file into array variables.

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
TXShooter
Posts: 165
Joined: 13 Dec 2017, 09:27

Need help with reading INI file into array variables.

02 Jun 2018, 09:36

For whatever reason (not enough coffee?), I just can not seem to grasp the concept of reading in an .ini file to arrays for use by variable[indexnum] in other parts of my script.

I know that a .ini file is supposed to be set up thus:
[SectionName]
Key=Value

And I know that an array has to be setup thus:
global SectionArray := []
global KeyArray := []

But what I can't seem to grasp is how to read and parse the file so that it gives me the 'variable[indexnum]' structure.
I.E. SectionArray[1] is expected to contain Event1, and SectionArray[2] is expected to contain Event2, etc.
KeyArray.Date[1] is expected to contain 2018.06.06, and KeyArray.Date[2] is expected to contain 2018.06.07, etc.
KeyArray.Speaker[1] is expected to contain Guest 1, etc.... you get my drift?

When an event is done, I need to write back to the file on the Completed key "Yes" replacing the "No" so it doesn't get processed in the next file read.

So, am I wrong to expect those variables to be filled that way with a parsing of an INI file, or am I just completely wrong?

Event.ini is written in the following fashion...

Code: Select all

[Event1]
Date=2018.06.06
Speaker=Guest 1
Title=TBD
StartTime=18:55
EndTime=19:30
M1=19:00
M2=19:29
Mic=22
[email protected],[email protected],[email protected]
Completed=No

[Event2]
Date=2018.06.07
Speaker=Guest 2
Title=TBD
StartTime=19:30
EndTime=20:00
M1=19:31
M2=19:59
Mic=10
[email protected],[email protected]
Completed=No

[Event3]
Date=2018.06.07
Speaker=Guest 5
Title=TBD
StartTime=15:00
EndTime=20:00
M1=16:31
M2=19:59
Mic=10,12,14,29,30,31,32
[email protected],[email protected]
Completed=No

...

[Event100]
Date=2018.06.012
Speaker=Guest 15
Title=TBD
StartTime=9:00
EndTime=11:00
M1=9:11
M2=10:49
Mic=11,12,13,14,15,16,17,18,29,30,31,32
[email protected],[email protected]
Completed=No
My code is so messed up now trying all kinds of different things, I don't even know what's right, what needs to be changed, and what needs to be deleted.

Code: Select all

	global DSYCEvent := ["Section", "Date", "Speaker", "Title", "StartTime", "EndTime", "M1", "M2"]
	global EventSections := {}
	global reaperEventDate := []
	global reaperEventSpeaker := []
	global reaperEventTitle := []
	global reaperEventStartTime := []
	global reaperEventEndTime := []
	global reaperEventM1Time := []
	global reaperEventM2Time := []
	...
	readIniFile("Event.ini")
	ExitApp
	
readIniFile(IniFile) ;
{
	SectionCount := 0
	IniRead, OutputVar, %IniFile%
	MsgBox, Read in %OutputVar%
/*  	Loop Parse, OutputVar, `n
	{	
		Section := A_LoopField
		MsgBox Section %Section%
		;IniRead, keys,%IniFile%, % Section
		;MsgBox, Keys: %keys%
 		;IniRead, reaperEventDate[%SectionCount%], %IniFile%, % Section, Date, %A_Space% ; results in an error
		;IniRead, reaperEventSpeaker, %IniFile%, % Section, Speaker, %A_Space%
		;IniRead, reaperEventTitle, %IniFile%, % Section, Title, %A_Space%
		;IniRead, reaperEventStartTime, %IniFile%, % Section, StartTime, %A_Space%
		;IniRead, reaperEventEndTime, %IniFile%, % Section, EndTime, %A_Space%
		;IniRead, reaperEventM1Time, %IniFile%, % Section, M1, %A_Space%
		;IniRead, reaperEventM2Time, %IniFile%, % Section, M2, %A_Space%
		;IniRead, reaperEventMic, %IniFile%, % Section, Mic, %A_Space%
		;I am so lost and confused now.
		SectionCount +=1
	}
 */
	return
}
I'm really hoping someone here smarter than I can help me out. I've got a major event coming up this next week that requires some AHK finesse and automation.
TXShooter
Posts: 165
Joined: 13 Dec 2017, 09:27

Re: Need help with reading INI file into array variables.

02 Jun 2018, 10:39

Is there a way to loop through and find out what and how many Sections there are, and then maybe loop through the keys and parse out their multiple entries?
Guest

Re: Need help with reading INI file into array variables.

02 Jun 2018, 12:53

Yes, use IniRead, OutputVarSectionNames, event.ini OutputVarSectionNames will be a linefeed (`n) delimited list of section names - try it
with MsgBox % OutputVarSectionNames and you'll see - this is described in the docs https://autohotkey.com/docs/commands/IniRead.htm
Now you can loop, parse, OutputVarSectionNames, n and read the data per event - check "OutputVarSection" in the docs ;)
TXShooter
Posts: 165
Joined: 13 Dec 2017, 09:27

Re: Need help with reading INI file into array variables.

02 Jun 2018, 15:23

Now I'm getting an error on trying to display the array[index]. (I've tried it with a 0 and a 1). It will display fine with out the index part, but only the very last entry to the INI file.

Code: Select all

readIniFile(IniFile) ;
{
	SectionsCount := 0
	IniRead, EventSections, %IniFile%
	MsgBox, Read in %EventSections%
  	Loop Parse, EventSections, `n
	{	EventSections := A_LoopField
 		IniRead, reaperEventDate, %IniFile%, % EventSections, Date
		IniRead, reaperEventSpeaker, %IniFile%, % EventSections, Speaker
		IniRead, reaperEventTitle, %IniFile%, % EventSections, Title
		IniRead, reaperEventStartTime, %IniFile%, % EventSections, StartTime
		IniRead, reaperEventEndTime, %IniFile%, % EventSections, EndTime
		IniRead, reaperEventM1Time, %IniFile%, % EventSections, M1
		IniRead, reaperEventM2Time, %IniFile%, % EventSections, M2
		IniRead, reaperEventMic, %IniFile%, % EventSections, Mic
		SectionCount +=1
	}
	MsgBox Date1: %reaperEventDate[0]% ; Throws error: The following variable name contains an illegal character: "reaperEventDate[0]" The program will exit.
	return
}
gregster
Posts: 8921
Joined: 30 Sep 2013, 06:48

Re: Need help with reading INI file into array variables.

02 Jun 2018, 15:36

For arrays you need to force expression mode via % with many commands which don't support it directly: :
https://autohotkey.com/docs/Variables.htm#Expressions wrote:Force an expression: An expression can be used in a parameter that does not directly support it (except OutputVar parameters) by preceding the expression with a percent sign and a space or tab. In [v1.1.21+], this prefix can be used in the InputVar parameters of all commands except the traditional IF commands (use If (expression) instead). This technique is often used to access arrays.

Code: Select all

reaperEventDate := ["one", "two", "three"]
msgbox % "Element 1: " reaperEventDate[1] 			; force expression

; expression mode is also possible with normal variables
for each, element in reaperEventDate			; loop through an array
	msgbox % "Index: " each " Element: " element    ; but here also possible: msgbox %each% %element% because 'each' and 'element' are not arrays
TXShooter
Posts: 165
Joined: 13 Dec 2017, 09:27

Re: Need help with reading INI file into array variables.

02 Jun 2018, 16:46

Code: Select all

MsgBox % "Date1: " reaperEventDate[1] ; Gives only the Key, but I want the Value.
That works, but only gives me the Key and not the Value(s), and only the value for the first Section in [Event1] no matter what number I put in the [Index]. I feel like I'm missing a loop iteration or something. Got any suggestions?
TXShooter
Posts: 165
Joined: 13 Dec 2017, 09:27

Re: Need help with reading INI file into array variables.

03 Jun 2018, 07:42

I'm missing a loop iteration, huh?
gregster
Posts: 8921
Joined: 30 Sep 2013, 06:48

Re: Need help with reading INI file into array variables.

03 Jun 2018, 10:18

One possibility (I used a shorter event.ini for demonstration purposes; add where indicated):

Code: Select all

/*    event.ini:
[Event1]
Date=2018.06.01
Speaker=Guest 1
Title=Title1

[Event2]
Date=2018.06.02
Speaker=Guest 2
Title=Title2

[Event3]
Date=2018.06.03
Speaker=Guest 3
Title=Title5
*/

inifile := "event.ini"
readIniFile(Inifile) 
ExitApp
;-----------------------------------------
readIniFile(IniFile) ;
{
	inikeys := ["Date", "Speaker", "Title"]					; add other keys you nedd
	for each, key in inikeys								; create one array per key
		reaperEvent%key% := []
	IniRead, EventSections, %IniFile%
	;MsgBox, Read in: `n`n%EventSections%
  	Loop Parse, EventSections, `n
	{	
 		section := A_loopfield, i := A_index
		for each, key in inikeys
		{	
			IniRead, output, %IniFile%, % section , % key
			reaperEvent%key%[i] := output
		}
	}
	loop % inikeys.length() 		; loop through number of keys in inikeys
		MsgBox % reaperEventDate[A_index] " - " reaperEventSpeaker[A_index] " - "  reaperEventTitle[A_index]		; check
	return
}
Esc::Exitapp
Might be preferable, to make the arrays global outside the function instead of creating them dynamically in the function (like I did), if they are all known anyway and needed outside. Of course, you could also let the function return an array/object of arrays or use an associative array from the start. Depends on what are you planning to do with it.
edited
Last edited by gregster on 03 Jun 2018, 10:58, edited 2 times in total.
SirRFI
Posts: 404
Joined: 25 Nov 2015, 16:52

Re: Need help with reading INI file into array variables.

03 Jun 2018, 10:36

Does it have to be ini? JSON or YAML are arrays/objects by default, so there's no extra struggle. Additionally, plenty other languages support JSON, allowing you to transfer data between programs.
Use

Code: Select all

[/c] forum tag to share your code.
Click on [b]✔[/b] ([b][i]Accept this answer[/i][/b]) on top-right part of the post if it has answered your question / solved your problem.
gregster
Posts: 8921
Joined: 30 Sep 2013, 06:48

Re: Need help with reading INI file into array variables.

03 Jun 2018, 10:47

I also prefer JSON - I use a lot of APIs, they mostly return this format.
TXShooter
Posts: 165
Joined: 13 Dec 2017, 09:27

Re: Need help with reading INI file into array variables.

03 Jun 2018, 11:00

I am unfamiliar with JSON or YAML as it applies to AHK. I can put these in any format. I just need to extract them as values later on.

Gregster,
I'm guessing that the keys have to be pre-defined in the script before they can be used in your example? I was kinda hoping this would be a little more dynamic than that... maybe it is but more code is required?
gregster
Posts: 8921
Joined: 30 Sep 2013, 06:48

Re: Need help with reading INI file into array variables.

03 Jun 2018, 11:36

The example should run as it is - with known keys of an ini file like I showed.

Dynamic in what sense? You could probably also extract all the available keys from each section, if that is what you are looking for:

Code: Select all

OutputVarSection
[v1.0.90+]: Omit the Key parameter to read an entire section.
imustbeamoron
Posts: 44
Joined: 18 Aug 2016, 22:56

Re: Need help with reading INI file into array variables.

03 Jun 2018, 14:50

TXShooter wrote:I am unfamiliar with JSON or YAML as it applies to AHK. I can put these in any format. I just need to extract them as values later on.
+1 for json. Its a much better solution than INI.

I use a couple of JSON functions found in the forum. maybe this will help:

Code: Select all

SetWorkingDir, % A_ScriptDir

;events array
events 				:= []

;###########################
;SAMPLE DATA
;###########################
;event1
eventObj 			:= {}
eventObj.Date		:= "2018.06.06"
eventObj.Speaker	:= "Guest 1"
eventObj.Title		:= "TBD"
eventObj.StartTime	:= "18:55"
eventObj.EndTime	:= "19:30"
eventObj.M1			:= "19:00"
eventObj.M2			:= "19:29"
eventObj.Mic		:= "22"
eventObj.MailToList	:= "[email protected],[email protected],[email protected]"
eventObj.Completed	:= false
events.push(eventObj)

;event2
eventObj 			:= {}
eventObj.Date		:= "2018.06.07"
eventObj.Speaker	:= "Guest 2"
eventObj.Title		:= "TBD"
eventObj.StartTime	:= "19:30"
eventObj.EndTime	:= "20:00"
eventObj.M1			:= "19:31"
eventObj.M2			:= "19:59"
eventObj.Mic		:= "10"
eventObj.MailToList	:= "[email protected],[email protected]"
eventObj.Completed	:= false
events.push(eventObj)

;event3
eventObj 			:= {}
eventObj.Date		:= "2018.06.07"
eventObj.Speaker	:= "Guest 5"
eventObj.Title		:= "TBD"
eventObj.StartTime	:= "15:00"
eventObj.EndTime	:= "20:00"
eventObj.M1			:= "16:31"
eventObj.M2			:= "19:59"
eventObj.Mic		:= "10,12,14,29,30,31,32"
eventObj.MailToList	:= "[email protected],[email protected]"
eventObj.Completed	:= false
events.push(eventObj)



;convert the events array to json
eventsJson := OBJ_to_JSON(events)

;here is what the json will look like.
MsgBox % eventsJson

;save the json to a file
fName := "eventJson.txt"
FileDelete, % fName		;-delete the file if it exists
FileAppend, % eventsJson,% fName
MsgBox % "Json file saved as : " fName
eventsJson := ""

;clear the events array
events := ""

;load the json from file, and convert to array
FileRead, eventsJson, % fName
events := JSON_to_OBJ(eventsJson)


;view the mic value of event 3
MsgBox % events[3].mic

;############################
;JSON Functions
;############################
;Convert JSON to AHK Object
;https://autohotkey.com/board/topic/93300-what-format-to-store-settings-in/#entry588268
;Credits to Getfree
JSON_to_OBJ(jsonStr)
{
    SC := ComObjCreate("ScriptControl") 
    SC.Language := "JScript"
    ComObjError(false)
    jsCode =
    (
    function arrangeForAhkTraversing(obj){
        if(obj instanceof Array){
            for(var i=0 ; i<obj.length ; ++i)
                obj[i] = arrangeForAhkTraversing(obj[i]) ;
            return ['array',obj] ;
        }else if(obj instanceof Object){
            var keys = [], values = [] ;
            for(var key in obj){
                keys.push(key) ;
                values.push(arrangeForAhkTraversing(obj[key])) ;
            }
            return ['object',[keys,values]] ;
        }else
            return [typeof obj,obj] ;
    }
    )
    SC.ExecuteStatement(jsCode "; obj=" jsonStr)
    return convertJScriptObjToAhks( SC.Eval("arrangeForAhkTraversing(obj)") )
}

convertJScriptObjToAhks(jsObj)
{
    if(jsObj[0]="object"){
        obj := {}, keys := jsObj[1][0], values := jsObj[1][1]
        loop % keys.length
            obj[keys[A_INDEX-1]] := convertJScriptObjToAhks( values[A_INDEX-1] )
        return obj
    }else if(jsObj[0]="array"){
        array := []
        loop % jsObj[1].length
            array.insert(convertJScriptObjToAhks( jsObj[1][A_INDEX-1] ))
        return array
    }else
        return jsObj[1]
}

IsNumber(Num)
{
    if Num is number
        return true
    else
        return false
}

;Convert AHK Object to JSON
;Originally Obj2Str() by Coco,
;http://www.autohotkey.com/board/topic/93300-what-format-to-store-settings-in/page-2#entry588373
OBJ_to_JSON(obj)
{
    str := "" , array := true
    for k in obj {
        if (k == A_Index)
            continue
        array := false
        break
    }
    for a, b in obj
        str .= (array ? "" : """" a """: ") . (IsObject(b) ?OBJ_to_JSON(b) : """" b """") . ", "
    str := RTrim(str, " ,")
    return (array ? "[" str "]" : "{" str "}")
}
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Need help with reading INI file into array variables.

03 Jun 2018, 15:15

It's quite possible to read ini sections/files into a variable, and parse them, resulting in associative arrays.

Code: Select all

q:: ;ini section to array
vPath := A_Desktop "\MyIni.txt"
vSection := "Event1"
IniRead, vText, % vPath, % vSection
MsgBox, % vText
vArray := "o" vSection
%vArray% := {} ;create an array called oEvent1
Loop, Parse, vText, `n, `r
{
	;note: StrSplit MaxParts requires v1.1.28+
	oTemp := StrSplit(A_LoopField, "=",, 2)
	if !(oTemp.Length() = 2)
		continue
	;MsgBox, % oTemp.1 "`r`n`r`n" oTemp.2
	%vArray%[oTemp.1] := oTemp.2
}
vOutput := ""
for vKey, vValue in %vArray%
	vOutput .= vKey " " vValue "`r`n"
MsgBox, % vOutput
return

;==================================================

w:: ;ini file to array
vPath := A_Desktop "\MyIni.txt"
FileRead, vText, % vPath
vArray := vArrayLast := ""
Loop, Parse, vText, `n, `r
{
	vTemp := A_LoopField
	if (vTemp ~= "^\[.*]$") ;a section header is detected
	{
		;show info for the previous section
		if !(vArray = "")
		{
			vOutput := ""
			for vKey, vValue in %vArray%
				vOutput .= vKey " " vValue "`r`n"
			MsgBox, % vArray "`r`n`r`n" vOutput
		}
		vArrayLast := vArray
		vSection := SubStr(vTemp, 2, -1)
		MsgBox, % vSection
		vArray := "o" vSection
		%vArray% := {} ;create an array called oEvent1
		continue
	}
	;note: StrSplit MaxParts requires v1.1.28+
	oTemp := StrSplit(A_LoopField, "=",, 2)
	if !(oTemp.Length() = 2)
	|| (vArray = "")
		continue
	;MsgBox, % oTemp.1 "`r`n`r`n" oTemp.2
	%vArray%[oTemp.1] := oTemp.2
}

;show info for the previous section
if !(vArrayLast = "")
{
	vOutput := ""
	for vKey, vValue in %vArray%
		vOutput .= vKey " " vValue "`r`n"
	MsgBox, % vArray "`r`n`r`n" vOutput
}

MsgBox, % "done"
return
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: Need help with reading INI file into array variables.

04 Jun 2018, 20:11

I would recommend JSON as well, though your data set is fairly simple so an ini should be fine. If you use JSON, I would recommend the JSON.ahk or jxon.ahk by coco https://github.com/cocobelgica/AutoHotkey-JSON
TXShooter
Posts: 165
Joined: 13 Dec 2017, 09:27

Re: Need help with reading INI file into array variables.

10 Jun 2018, 16:17

gregster wrote:Dynamic in what sense?
Roughly put... dynamic in the sense of reading into one array the different [SectionNames], and then read into two different arrays the "Keys","Values". (Or is that Static?)

Array.SectionNames[Event1, Event2, Event3, ... (last Section Name)]
Array.SectionNames.KeyNames[Date, Speaker, Title, etc... (last Key Name under that Section)]
Array.SectionNames.ValueNames[2018.06.06, Guest 1, TBD, etc...(Last Value Name under that Section)}

So that I could assign to new variables...
X = Array.SectionNames[3] ; Would be "Event3"
or maybe like...
Y = Array.SectionNames[3].ValuesNames[1] ; Would be "2018.06.06"


I dunno if any of that is even possible in this language, but some of the examples that I skimmed over (or rather, some of the forum posts) seemed to indicate this kind of setup was kinda feasible. However, when I went to read exactly how ini files and arrays were handled, .... yeah, that's where I got lost. Maybe I'm just completely backwards on how these two things relate to each other.

So... I've come here to get unlost... and now JSON is being offered as a solution (which might could work, but I've already got my other scripts writing INI files, and I'd like to stick with that if possible).
coffee
Posts: 133
Joined: 01 Apr 2017, 07:55

Re: Need help with reading INI file into array variables.

11 Jun 2018, 00:19

This throws all sorts of flags...
TXShooter wrote: I dunno if any of that is even possible in this language
It is, but you seem to be asking for a custom solution, seeing what you posted. Not a simple iniread and write. Your requirements also seem indecisive. You may also have to change how you are doing it. Why don't you just treat each event as an object, they are like the prime candidate for it. You don't need an array for each event field. You need an event as an object that contains fields.

Due to changes in the latest autohotkey v1 version (for ojbcount), I would simply go with an associative array and a rename of [Event1], [Event2], etc, in the ini to simply be an integer, i.e [1] and [2] and add a field inside the event called name, that will contain "Event1" or whatever name you want to give it. I would also suggest including as field the number as "ID", e.g ID = 1 or ID = 2.

So events[1] pulls event object attached to section name [1] in the ini (and not the first section found), and events[1].name pulls the name of event 1 i.e "Event1", events[1].date the date, etc.

If you ever need the count of this events object, then objcount() solves it, allowing you to create sparse objects, with keys 1, 3, 100 for example. Events[3] can return event 3, events being a conceptual associative array instead of linear, i.e 3 is not the "third" key by order, but a key called 3, similar to obj["boo"], boo being the key name.
TXShooter wrote: so it doesn't get processed in the next file read.
You either read the whole ini file, parse it, store it into an object, manipulate what you need, then write back the whole thing overwriting it, or, parse the object and use iniwrite for each key value, but I think this is slower since the file has to be opened and closed each time for each ini function call.
Ultimately, reading the whole file and parsing it is less headachey.

Tip, autohotkey associative array keys are always stored in alphabetical order, instead of natural or the original order they were added. If you try to use a hypothetical event object with field names just as in the ini, the write back to file wont be in the order you have right now, unless you use iniwrite for each individual key value and not in bulk using pairs. Or if you try to use the sectionnames as keys in an associative array, the order of the sections may also get changed, as in "Event1", "Event100", "Event2", "Event3".

Are people editing the ini file manually or is it being exported from somewhere else?
Does the order of the data in the ini file matter? Does event1 need to be right in the first line? Another important question, does the order of each field in the ini file matter? (none of these should be a requirement)
Are events completed in order? (shouldn't be a requirement either)
If the order of the ini file matters, you want to use the data store as the viewer. That's even worse implementation from the getgo.
In your current way with fixed positions, if you decide to add another field to the event in the future, say something above "speaker", then Speaker is no longer [2], but [3] when bound to a fixed position. You now have to change every reference of [2] to [3] in the code, instead of simply pulling the fields or sections by name.

What does the section name stand for? the "event1" , "event2"? Is that the name of the event? Or is it the unique identifier? If it's the latter, why are you prefixing everything with "event", i think it should be pretty obvious what the ini file is for. Why not keep it as simple integers? You are reading an ini file containing event objects and their fields.

Code: Select all

[1]
Date=2018.06.06
....
You say "X = Array.SectionNames[3] ; Would be "Event3"", ? so which is it, what's Event3 here? the event name?
"Event3" as in the object reference to "Event3" or "Event3" the string?
Isn't it more reasonable to actually do something like Array[3].name returns "Event3" string? with Array[3].date returning the date and so on? and Array[3] returning an object reference for event 3.
I assume "Event3" is like an internal name? and the title field is the name in the promotional material?

I edited some functions I had for other stuff to match this, using your current section names, to see if they help you figure out what you need to do or continue doing. You can put stuff inside a class, or whatever you come up with. No warranties or liabilities, so make a backup of the original ini file if you decide to try anything. I would also use JSON since it is way more compatible with other stuff and flexible.
Only problem being... it's written in Autohotkey v2, so... ¯\_(ツ)_/¯

Code: Select all

events := LoadEvents("events.ini")
Msgbox(events.3.id) ;// Shows 3
Msgbox(events.3.name) ;// Shows Event3
Msgbox(events.3.date) ;// Shows 2018.06.07

hello := events.3 ;// Copies event 3 object reference to hello
;// So you can do
Msgbox(hello.name) ;// Shows Event3

events.3.completed := "yes" ;// Sets completion

if eventsInProg := GetEventsByProgress(events, "no")
{
	for k,v in eventsInProg
		msgbox(k) ;// 1, 2 and 100.
	eventsInProg.2.title:="HEEEEEEEEEEEEY"
}

UpdateEvents("events.ini", events) ;// Keeps order in existing file
DumpEvents("events-unordered.ini", events) ;// Won't keep order in any way.


;////////////////////////////////////////////////////////////////////
/* LoadEvents

	Path: path to ini file
	-
	Return: associative array of ini elements
*/
LoadEvents(path)
{
	;// Inline comments unsupported
	if !path || !FileExist(path)
		throw "Ini file does not exist."

	sections := {}
	sectionName := "•¶" ;// Non standard characters to ensure key value pairs are always inside a section
	;// since an empty section name is possible for winapi i.e []
	line := firstChar := key := value := ""
	i := j := 0
	
	Loop read, path
	{
		line := Trim(a_loopreadline) ;// QOL
		firstChar := SubStr(line, 1, 1) ;// QOL
		
		if !line || (firstChar = ";") ;// Empty/Comment line
			continue
		
		if (firstChar = "[") ;// Section definition
		{
			if !(j :=InStr(line, "]",, 2))
				throw "Malformed section definition in ini file."

			sectionName := SubStr(line, 2, j-2) ;// Can be empty
			ID:=SubStr(sectionName, 6) ;// Get N from EventN
			
			;// Store EventN as event.name and the ID/number as event.ID simply because objects
			;//	should contain their own information by themselves. That way even if the ID key is lost, the data always
			;//	resides inside the object. e.g eventvar:=events[id], now you don't know what number it is.
			;// That means the current implementation of using "Event5" is bad :)
			;// Or using an ini file for this is bad :D
			;// Ini = initialization, not database.
			sections[ID] := Object("Name", sectionName, "ID", ID)
			continue
		}

		if (i := Instr(line, "="))
		{
			if (sectionName = "•¶")
				throw "Every key value pair needs to be within a section definition, even if []"
				
			key := SubStr(line, 1, i-1) ;// Left of =
			value := SubStr(line, i+1) ;// Right of =
			sections[ID][key] := value ;// Store it
		}
		else
			continue ;// Line not recognized. Neither section definition nor key-value pair.
	}
	
	return sections
}

/* GetEventsByProgress

Events: associative array containing events
Progress: "yes" or "no"
-
Return: associative array containing events with the matching progress.
*/
GetEventsByProgress(events, progress)
{
	matched := {}
	count := 0
	for id, event in events
	{
		if (event.completed = progress)
		{
			matched[id] := event ;// Will be storing object reference.
			;// Any changes here will also be in the original array where the ini was loaded to.
			++count
		}
	}
	return (count ? matched : "")
}

/* ExportEvents

File: filepath of ini file
Events: associative array containing events
-
Return: empty
*/
UpdateEvents(file, events)
{
	;// pairs:=""
	for id, event in events
	{
		section:=event.name
		for key, value in event
		{
			if (key = "name") || (key = "id") ;// Accounting for bad implementation
				continue

			IniWrite(value, file, section, key) ;// Preserves order if they already exist in the ini file.
			;// Using the iniwrite gem where file is the second parameter.
			;// pairs .= key "=" value "`n"
		}
		;// IniWrite(pairs, "initest.ini", section) ;// Won't preserve order.
		;// pairs:=""	
	}
}

/* DumpEvents

Same same, but different, but still same.
*/
DumpEvents(file, events)
{
	data:=""
	for id, event in events
	{
		data .= "[" event.name "]`n"
		for key, value in event
		{
			if (key = "name") || (key = "id")
				continue
			data .= key "=" value "`n"
		}
	}
	
	if FileExist(file)
		FileRecycle(file) ;// So you can get it back if you fuck up.
	FileAppend(data, file) ;// Another gem where the file is the second parameter
}


;// RIP custom ObjCount() 2014-2018
ObjCount(obj)
{
	return NumGet(&obj + 4*A_PtrSize)
}

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: mikeyww and 148 guests