 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
majkinetor
Joined: 24 May 2006 Posts: 4116 Location: Belgrade
|
Posted: Fri Aug 31, 2007 2:34 pm Post subject: |
|
|
I added link to your function to the first post.
Thx for your 3 minutes, and I am glad to hear that you have 2 minutes left for something else.
| Quote: | | I'll wait on you for the reverse functions lol. |
Ofcourse. I will do slow version and send you for optimisation if you can spare another minute. _________________
 |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 4116 Location: Belgrade
|
Posted: Fri Sep 21, 2007 11:25 am Post subject: |
|
|
2Titan
I finaly had time to check out your version, and it was like i was telling you, not good.
First the point is to make function universal, that is to respond on all cases of ini files:
For instance
| Code: | | If InStr(A_LoopReadLine, "[") = 1 |
is one of such mistakes cuz I can have ini files like this:
| Code: | [section1]
hej1= value
[section2]
hej = value |
in which case section2 will not be spoted, while IniRead does this nicely.
When you account all that iregular variants of regular ini files, your code will get somewhat bigger and thus will not work that faster as RE as it is entirely executed in C code
Well, you can try in another 3 minuts to solve mentioned problems. Its not a big deal after all, but we got to 6 now
In other way, the point of your function was not the same as point of the mine so it can't replace 2 functions I gave. Its not point to parse everything into global vars, but to have Ini framework that works with strings in INI form as much as with INI files. _________________
 |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 4473 Location: Qld, Australia
|
Posted: Fri Sep 21, 2007 3:51 pm Post subject: |
|
|
I recently started to write ini file reading/parsing code for one of the scripts I'm working on, but happily deleted it all when I found GetPrivateProfileSection and related functions.
Here are the wrappers I'm using, in case they're of some use to someone: | Code: | ; Reads an entire section of an ini file, excluding comments.
INI_ReadSection(Filename, Section)
{
; Expand relative paths, since GetPrivateProfileSection only searches %A_WinDir%.
Loop, %Filename%, 0
Filename := A_LoopFileLongPath
VarSetCapacity(text, 0x7FFF, 0)
len := DllCall("GetPrivateProfileSection"
, "str", Section, "str", text, "uint", 0x7FFF, "str", Filename)
; Each line within the section is terminated with a null character.
; Replace each delimiting null char with a newline:
Loop, % len-1
if (NumGet(text, A_Index-1, "UChar") = 0)
NumPut(10, text, A_Index-1, "UChar") ; \0 -> \n
; Windows Me/98/95:
; The returned string includes comments.
;
; This removes comments. Also, I'm not sure if leading/trailing space is
; automatically removed on Win9x, so the regex removes that too.
if A_OSVersion in WIN_ME,WIN_98,WIN_95
text := RegExReplace(text, "m`n)^[ `t]*(?:;.*`n?|`n)|^[ `t]+|[ `t]+$")
return text
}
; Replaces the content of a section,
; from [section] to the last key=value line.
INI_WriteSection(Filename, Section, Content)
{
Loop, %Filename%, 0
Filename := A_LoopFileLongPath
if (SubStr(Content,0) != "`n")
Content .= "`n" ; `n -> section null-terminator
Loop, % StrLen(Content)
if (NumGet(Content, A_Index-1, "UChar") = 10)
NumPut(0, Content, A_Index-1, "UChar") ; \n -> \0
; Note: This deletes ALL existing content between [Section] and the last
; key=value line, but not trailing lines which have no '='.
return DllCall("WritePrivateProfileSection"
, "str", Section, "str", Content, "str", Filename)
}
; Gets the names of all sections in an ini file.
INI_GetSectionNames(Filename)
{
; Expand relative paths, since GetPrivateProfileSectionNames only searches %A_WinDir%.
Loop, %Filename%, 0
Filename := A_LoopFileLongPath
VarSetCapacity(text, 0x1000, 0)
len := DllCall("GetPrivateProfileSectionNames", "str", text, "uint", 0x1000, "str", Filename)
; Replace each delimiting null char with a newline:
Loop, % len-1
if (NumGet(text, A_Index-1, "UChar") = 0)
NumPut(10, text, A_Index-1, "UChar") ; \0 -> \n
return text
} | Very little parsing is necessary, as the Win32 API does most of the work. |
|
| Back to top |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5043 Location: /b/
|
Posted: Fri Sep 21, 2007 4:29 pm Post subject: |
|
|
I had AutoTrim in my code anyway so just replace the relevant lines of code with:
| Code: | Loop, Read, %src%
{
l = %A_LoopReadLine%
If InStr(l, "[") = 1
{
StringMid, s, l, 2, InStr(l, "]") - 2 |
My point was not only about speed but the fact that complex regex which even veterans like Skan and engunneer struggle with can be avoided with simple string functions or Win API as lexikos nicely demonstrated above (ever head the expression: you don't need a bulldozer to build a sandcastle??). _________________ Chat (IRC) • PlusNet • Scripts • IronAHK • Contact by email not private message. |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 4116 Location: Belgrade
|
Posted: Fri Sep 21, 2007 9:17 pm Post subject: |
|
|
| Quote: | | My point was not only about speed but the fact that complex regex which even veterans like Skan and engunneer struggle with |
It seems all of you didn't do your homework, rofl
| Quote: | | I recently started to write ini file reading/parsing code for one of the scripts I'm working on, but happily deleted it all when I found GetPrivateProfileSection and related functions. |
I am aware of all system ini functions and I intentionaly choosed to avoid them. Can't remember right now what was the reason... perhaps I have currently to much alchohol in my blood
| Quote: | | (ever head the expression: you don't need a bulldozer to build a sandcastle??) |
I prefer to use bulldozer if it is already at the spot and ready for work. rofl  _________________
 |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 4116 Location: Belgrade
|
Posted: Tue Dec 18, 2007 4:28 pm Post subject: |
|
|
New version
Documentation is online now. _________________
 |
|
| Back to top |
|
 |
Dragonscloud
Joined: 16 Jul 2005 Posts: 95
|
Posted: Tue Dec 18, 2007 9:55 pm Post subject: |
|
|
| majkinetor wrote: |
I am more concerned currently about API that is extremely practical and easy to use in most cases.
|
I'm not dissing anyone else's viewpoints here, but thanks for writing a set of functions that I find both useful and fairly easy to use.
Regardless of how well-coded or well-optimized a function is, it's useless to me if I can't figure out how to get it to work.
I also like the flexibility,and I learned a little syntax candy from reading your code, too.
Great documentation, btw. _________________ “yields falsehood when preceded by its quotation” yields falsehood when preceded by its quotation. |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 4116 Location: Belgrade
|
Posted: Wed Dec 19, 2007 12:06 am Post subject: |
|
|
Thank you  _________________
 |
|
| Back to top |
|
 |
bmcclure
Joined: 24 Nov 2007 Posts: 766
|
Posted: Wed Dec 19, 2007 5:07 am Post subject: |
|
|
I really like these functions too. I'm going to start using them!
I use AHKArray in my script, but for some things that just seems slightly like overkill. In those cases, this should do the trick nicely to avoid having to write a bunch of different globals!
I could probably even load all my program settings with this and parse them on the fly rather than have a global per-setting. That would be interesting!
Thanks for the cool functions majkinetor... (as usual ) _________________ Ben
My Trac projects
My Wiki
[Broken] - My music |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 4116 Location: Belgrade
|
Posted: Wed Dec 19, 2007 9:49 am Post subject: |
|
|
| Quote: | | I could probably even load all my program settings with this and parse them on the fly rather than have a global per-setting. |
Thats one of the points of the module. You can just call Ini_LoadSections("config.ini") and start to use settings imediately in the manner %Section_key%. So, instead calling IniRead multiple times, you do only one func call, which is also faster then multiple InIReads.
Keep in mind that you can use functions on any regular string. You can use it to return multiple values from the function, for instance:
| Code: | fun(...) {
;here we have values in val1, val2, val3... valN
;now we make the section format
loop, N
res .= "ret" %A_Index% "=" val%A_Index% "`n"
return res
}
Ini_GetVal( fun(), "ret5") ;get ret value 5
Ini_LoadKeys("", fun(), "", "fun_") ;makes fun_ret1, fun_ret2 ... fun_retN
vals := Ini_LoadKeys("", fun(), "vals") ;get only values function returned....
loop, parse, %vals%, `n
;do something with values here
|
And so on...
| Quote: | | Thanks for the cool functions majkinetor |
Thanks  _________________
 |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 4116 Location: Belgrade
|
Posted: Wed Dec 19, 2007 4:00 pm Post subject: |
|
|
v1.0 b2
Big update, added MakeSection function which is reverse function of LoadKeys, so this should produce the same section string as input (up to the trimming of key name):
| Code: | s =
(
key1=blah blah
mykey= what now ?
thirdOne= >.<
)
Ini_LoadKeys("", s, "", "section")
s1 := Ini_MakeSection("section_")
msgbox % s1 |
Keep in mind that this function is xperimental anyway, and in some weird cases it may fail. See this _________________
 |
|
| Back to top |
|
 |
bmcclure
Joined: 24 Nov 2007 Posts: 766
|
Posted: Thu Dec 27, 2007 7:27 pm Post subject: |
|
|
Either I'm doing something wrong or I'm just getting some unexpected results here.
Here is the code that loads from my config file:
| Code: | ReadConfig:
FileCopy,res\default\config.ini.default,%ConfigFile%,0
configSections := Ini_GetSectionNames(ConfigFile)
Loop, Parse, configSections, `n
If (A_LoopField <> "Disabled")
Ini_LoadKeys(ConfigFile, A_LoopField, 0, "cfg_" . A_LoopField . "_")
If Not cfg_SteamLab_LastRun
GoSub,ShowSettings
Return |
And here is the code that saves back to it:
| Code: | WriteConfig:
Loop, Parse, configSections, `n
If (A_LoopField <> "Disabled") {
section := Ini_MakeSection("cfg_" . A_LoopField . "_")
Ini_ReplaceSection(ConfigFile, A_LoopField, section)
}
Return |
Here is the original config file:
| Code: | [SteamLab]
LastRun=
LoadFont=Share-TechMono.ttf
Icon=res\ico\SteamLab.ico
[Schedule]
Enable=0
CheckDuration=3
LastCheck=
[Backup]
GameDir=backup\games
FileDir=backup\files
[Steam]
Version=
Username=
Password=
RunOnStart=1
LockPassword=
Locked=0
DownloadURL=http://storefront.steampowered.com/download/SteamInstall.msi
RegKey=HKEY_CURRENT_USER\Software\Valve\Steam\SteamPath
[Crosus]
Enable=0
Version=
Username=
Password=
DownloadURL=http://www.isotx.com/CrosuSInstaller.exe
[OBMM]
Enable=0
Version=
DownloadURL=http://timeslip.chorrol.com/current/obmm.zip
RegKey=HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Oblivion mod manager_is1\InstallLocation
[SteamDock]
Enable=1
Enabled=0
[OSD]
Color=Blue
Font=Share-TechMono
[Hotkeys]
Enable=1
[Screensaver]
Disabled=1
[SteamWin]
BackupManW=450
BackupManH=292
BackupManX=
BackupManY=
BackupManGui=14
KeyManW=
KeyManH=
KeyManX=
KeyManY=
HotkeyManW=
HotkeyManH=
HotkeyManX=
HotkeyManY=
SettingsW=
SettingsH=
SettingsX=
SettingsY= |
Here is the config file after being loaded, some values being updated, and it being saved with the above function:
| Code: | [SteamLab]
Icon=
LastRun=20071227121912
LoadFont=
SteamLab_Icon=
SteamLab_LastRun=20071227114235
[Schedule]
CheckDuration=
Enable=
Schedule_CheckDuration=
Schedule_Enable=
Schedule_LastCheck=
[Backup]
[Steam]
RunOnStart=
Steam_DownloadURL=
Steam_Locked=
Steam_LockPassword=
Steam_Path=0
Steam_PID=
Steam_RegKey=
Steam_RunOnStart=
[Crosus]
Crosus_DownloadURL=
Crosus_Enable=
Crosus_Path=
Crosus_Path_bG=SetCrosusPath
Crosus_Path_bH=28
Crosus_Path_bO=x+0 yp-6
Crosus_Path_bW=76
Crosus_Path_hwnd=0xb0386
Crosus_Pathb1=1443172427
Crosus_Pathb1_ro=1225068657
Crosus_PID=
Crosus_Version=
Enable=
[OBMM]
Enable=
OBMM_Enable=
OBMM_Path=
OBMM_PID=
OBMM_RegKey=
[Dock]
Dock_aClient[0]=
Dock_Enable=
Dock_Enabled=
Dock_hHook1=
Dock_hHook2=
Dock_hHook3=
Dock_hookProcAdr=
Dock_HostDied=
Dock_HostID=
Dock_OnHostDeath=
Dock_s1=
[OSD]
OSD_Color=
[Hotkeys]
Enable=
Hotkeys_Enable=
Hotkeys_Section= |
I don't understand several things.
What happened to all my [Backup] values?
Why did my Dock_ variables get put in a section even though there was no Dock section to begin with?
Should there not be two underscores in the prefix? It seems to be writing the name as everything after the first underscore.
I don't have any variables such as cfg_Crosus_Path_bG
or cfg_Crosus_Path_bH
so it must be getting those values from the variables Crosus_Path_bG and Crosus_Path_bH
Update: Even if I remove the first underscore from the prefix, it still removes all the keys under [Backup], removes the empty line in-between sections, is not saving my loaded variables back to the file, only ones I've set afterward. _________________ Ben
My Trac projects
My Wiki
[Broken] - My music |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 4116 Location: Belgrade
|
Posted: Thu Dec 27, 2007 9:54 pm Post subject: |
|
|
It seems this is a bug in MakeSection code. I will check it out as soon as I can.
About other usage, u can achieve the same as above significantly faster with just 1 command:
| Code: | ReadConfig:
FileCopy,res\default\config.ini.default,%ConfigFile%,0
configSections := Ini_GetSectionNames(ConfigFile)
Loop, Parse, configSections, `n
If (A_LoopField <> "Disabled")
Ini_LoadKeys(ConfigFile, A_LoopField, 0, "cfg_" . A_LoopField . "_")
If Not cfg_SteamLab_LastRun
GoSub,ShowSettings
Return |
| Code: | | Ini_LoadKeys(ConfigFile, "", 0, "cfg_") |
The bad thing here is that Disabled will also be loaded as there is no filter for sections in this mode. However, you may use filter if all keys in the Disabled section have common prefix. Like this, ini file is read only once, wile in your code it will be read as the number of sections in it. You can also use second mechanism, to first call Ini_LoadSection(ConfigFile, "") to load all sections in global section strings, and then feed strings to Ini_LoadKeys and blank for file name. That will also be much faster and ini is again read only once. This way you can also delete Disabled section with inis_Disabled := ""
Keep in mind that MakeSection is experimental function, and it will fail if you have large number of variables due to the limitations of AHK. This is not the case here however.
I currently discourage its usage but its ofcourse xtremely handy - your entire configuration work can be done with it in few lines as you demonstrated, reglardles of number of configuration options. Actually, with the code you wrote you don't have to think about Ini ever again (when I fix MakeSection ofc). Contrary to that, standard AHK ini handling would need much much more lines of code and constant maintance when adding/ removing options. _________________
 |
|
| Back to top |
|
 |
bmcclure
Joined: 24 Nov 2007 Posts: 766
|
Posted: Fri Dec 28, 2007 12:47 am Post subject: |
|
|
Heh, imagine my surprise when all my Dock() globals showed up in my config file
That's why the functions are so attractive I used to use tons of Ini, Writes and Ini, Reads to save and load, but every time I made a change to the config file I had to update the code. Once the function works right I'll hopefully be able to create whatever options I want and just conform my code to the Ini prefixes so that I work directly with the config variables. I've already made most of the changes in my code, but SteamLab isn't currently working properly due to those new saving and loading functions (or I guess probably just the MakeSection code)
Now that I think about it, I might as well just pull the Disabled variables in with the Ini code anyway, so that ultimately those variables can be accessed (and therefore re-enabled) if needed by the script later on. It shouldn't hurt anything I suppose. So I'll shorten my loading function up. Thanks for the tip
Now if the saving function worked properly I think I'd be in business!
| Code: | ReadConfig:
FileCopy,res\default\config.ini.default,%ConfigFile%,0
configSections := Ini_GetSectionNames(ConfigFile)
Ini_LoadKeys(ConfigFile, "", 0, "cfg_")
If Not cfgSteamLab_LastRun
GoSub,ShowSettings
Return
WriteConfig:
Loop, Parse, configSections, `n
{ section := Ini_MakeSection("cfg_" . A_LoopField . "_")
Ini_ReplaceSection(ConfigFile, A_LoopField, section)
}
Return |
_________________ Ben
My Trac projects
My Wiki
[Broken] - My music
Last edited by bmcclure on Fri Dec 28, 2007 1:29 am; edited 1 time in total |
|
| Back to top |
|
 |
bmcclure
Joined: 24 Nov 2007 Posts: 766
|
Posted: Fri Dec 28, 2007 1:23 am Post subject: |
|
|
(when makesection works) would this be faster than doing a ReplaceSection for each section?
| Code: | WriteConfig:
configFileNew := ""
Loop, Parse, configSections, `n
configFileNew .= "[" . A_LoopField . "]`n" . Ini_MakeSection("cfg_" . A_LoopField . "_") . "`n`n"
FileDelete, %ConfigFile%
FileAppend, %configFileNew%, %ConfigFile%
Return |
I figure that way it only makes two file operations instead of one per section.
Update: Hey, good news. I tried my script with the above code, and aside from the bogus keys that MakeSection inserts, the Ini File is looking great now:
| Code: | [SteamLab]
Icon=
LastRun=20071227181234
LoadFont=
SteamLab_LastRun=20071227124654
SteamLab_LoadFont=
SteamLab_SteamLab_Icon=res\ico\SteamLab.ico
SteamLab_SteamLab_LastRun=
SteamLab_SteamLab_LoadFont=Share-TechMono.ttf
[Schedule]
CheckDuration=
Enable=
Schedule_CheckDuration=
Schedule_Enable=
Schedule_Schedule_CheckDuration=3
Schedule_Schedule_Enable=0
Schedule_Schedule_LastCheck=
[Backup]
Auto=
Backup_Auto=
Backup_Backup_Auto=1
Backup_Backup_FileDir=backup\files
Backup_Backup_GameDir=backup\games
[Steam]
AutoRun=
Steam_AutoRun=
Steam_Steam_AutoRun=1
Steam_Steam_DownloadURL=http://storefront.steampowered.com/download/SteamInstall.msi
Steam_Steam_Locked=0
Steam_Steam_LockPassword=
Steam_Steam_Password=
Steam_Steam_RegKey=HKEY_CURRENT_USER\Software\Valve\Steam\SteamPath
Steam_Steam_Username=
Steam_Steam_Version=
[Crosus]
Crosus_Crosus_DownloadURL=http://www.isotx.com/CrosuSInstaller.exe
Crosus_Crosus_Enable=0
Crosus_Crosus_Password=
Crosus_Crosus_Username=
Crosus_Crosus_Version=
Crosus_Enable=
Enable=
[OBMM]
Enable=
OBMM_Enable=
OBMM_OBMM_DownloadURL=http://timeslip.chorrol.com/current/obmm.zip
OBMM_OBMM_Enable=0
OBMM_OBMM_RegKey=HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Oblivion mod manager_is1\InstallLocation
OBMM_OBMM_Version=
[SteamDock]
Enable=
SteamDock_Enable=
SteamDock_SteamDock_Enable=1
SteamDock_SteamDock_Enabled=0
[OSD]
OSD_OSD_Color=Blue
OSD_OSD_Font=Share-TechMono
[Hotkeys]
Enable=
Hotkeys_Enable=
Hotkeys_Hotkeys_Enable=1
[Screensaver]
Screensaver_Screensaver_Disabled=1
[SteamWin]
SettingsH=228
SettingsW=369
SettingsX=655
SettingsY=396
SteamWin_SettingsH=228
SteamWin_SettingsW=369
SteamWin_SettingsX=655
SteamWin_SettingsY=396
SteamWin_SteamWin_BackupManGui=14
SteamWin_SteamWin_BackupManH=292
SteamWin_SteamWin_BackupManW=450
SteamWin_SteamWin_BackupManX=
SteamWin_SteamWin_BackupManY=
SteamWin_SteamWin_HotkeyManH=
SteamWin_SteamWin_HotkeyManW=
SteamWin_SteamWin_HotkeyManX=
SteamWin_SteamWin_HotkeyManY=
SteamWin_SteamWin_KeyManH=
SteamWin_SteamWin_KeyManW=
SteamWin_SteamWin_KeyManX=
SteamWin_SteamWin_KeyManY=
SteamWin_SteamWin_SettingsH=
SteamWin_SteamWin_SettingsW=
SteamWin_SteamWin_SettingsX=
SteamWin_SteamWin_SettingsY= |
At least my dock() globals are nowhere to be found in there now, and my [Backup] keys show up now  _________________ Ben
My Trac projects
My Wiki
[Broken] - My music |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|