我正在尝试读取.ini
具有以下格式的文件:
[SectionName]
total=4
[AnotherSectionName]
total=7
[OtherSectionName]
total=12
基本上我想从.ini
文件中打印出某些值,例如下面的总数,OtherSectionName
然后是来自的总数AnotherSectionName
。
我正在尝试读取.ini
具有以下格式的文件:
[SectionName]
total=4
[AnotherSectionName]
total=7
[OtherSectionName]
total=12
基本上我想从.ini
文件中打印出某些值,例如下面的总数,OtherSectionName
然后是来自的总数AnotherSectionName
。
这是一个命令文件 ( ini.cmd
),您可以使用它来提取相关值:
@setlocal enableextensions enabledelayedexpansion
@echo off
set file=%~1
set area=[%~2]
set key=%~3
set currarea=
for /f "usebackq delims=" %%a in ("!file!") do (
set ln=%%a
if "x!ln:~0,1!"=="x[" (
set currarea=!ln!
) else (
for /f "tokens=1,2 delims==" %%b in ("!ln!") do (
set currkey=%%b
set currval=%%c
if "x!area!"=="x!currarea!" if "x!key!"=="x!currkey!" (
echo !currval!
)
)
)
)
endlocal
这是一个显示它的成绩单(我手动缩进了输出以使其更易于阅读):
c:\src>type ini.ini
[SectionName]
total=4
[AnotherSectionName]
total=7
[OtherSectionName]
total=12
c:\src>ini.cmd ini.ini SectionName total
4
c:\src>ini.cmd ini.ini AnotherSectionName total
7
c:\src>ini.cmd ini.ini OtherSectionName total
12
cmd
要在另一个文件中实际使用它,只需将echo %val%
下面的行替换为您想要对其执行的任何操作):
for /f "delims=" %%a in ('call ini.cmd ini.ini AnotherSectionName total') do (
set val=%%a
)
echo %val%
我知道我参加聚会有点晚了,但我决定编写一个通用的 ini 文件实用程序批处理脚本来解决这个问题。
该脚本将允许您检索或修改 ini 样式文件中的值。它的搜索不区分大小写,并且在 ini 文件中保留空白行。从本质上讲,它允许您将 ini 文件作为一种非常基本的数据库进行交互。
如果您只读取/写入对cmd
解释器没有特殊含义的字母数字值或符号,则此脚本将正常工作。如果您需要能够处理包含与号、百分比等值的东西,请参阅下面的更新部分。
:: --------------------
:: ini.bat
:: ini.bat /? for usage
:: --------------------
@echo off
setlocal enabledelayedexpansion
goto begin
:usage
echo Usage: %~nx0 /i item [/v value] [/s section] inifile
echo;
echo Take the following ini file for example:
echo;
echo [Config]
echo password=1234
echo usertries=0
echo allowterminate=0
echo;
echo To read the "password" value:
echo %~nx0 /s Config /i password inifile
echo;
echo To change the "usertries" value to 5:
echo %~nx0 /s Config /i usertries /v 5 inifile
echo;
echo In the above examples, "/s Config" is optional, but will allow the selection of
echo a specific item where the ini file contains similar items in multiple sections.
goto :EOF
:begin
if "%~1"=="" goto usage
for %%I in (item value section found) do set %%I=
for %%I in (%*) do (
if defined next (
if !next!==/i set item=%%I
if !next!==/v set value=%%I
if !next!==/s set section=%%I
set next=
) else (
for %%x in (/i /v /s) do if "%%~I"=="%%x" set "next=%%~I"
if not defined next (
set "arg=%%~I"
if "!arg:~0,1!"=="/" (
1>&2 echo Error: Unrecognized option "%%~I"
1>&2 echo;
1>&2 call :usage
exit /b 1
) else set "inifile=%%~I"
)
)
)
for %%I in (item inifile) do if not defined %%I goto usage
if not exist "%inifile%" (
1>&2 echo Error: %inifile% not found.
exit /b 1
)
if not defined section (
if not defined value (
for /f "usebackq tokens=2 delims==" %%I in (`findstr /i "^%item%\=" "%inifile%"`) do (
echo(%%I
)
) else (
for /f "usebackq delims=" %%I in (`findstr /n "^" "%inifile%"`) do (
set "line=%%I" && set "line=!line:*:=!"
echo(!line! | findstr /i "^%item%\=" >NUL && (
1>>"%inifile%.1" echo(%item%=%value%
echo(%value%
) || 1>>"%inifile%.1" echo(!line!
)
)
) else (
for /f "usebackq delims=" %%I in (`findstr /n "^" "%inifile%"`) do (
set "line=%%I" && set "line=!line:*:=!"
if defined found (
if defined value (
echo(!line! | findstr /i "^%item%\=" >NUL && (
1>>"%inifile%.1" echo(%item%=%value%
echo(%value%
set found=
) || 1>>"%inifile%.1" echo(!line!
) else echo(!line! | findstr /i "^%item%\=" >NUL && (
for /f "tokens=2 delims==" %%x in ("!line!") do (
echo(%%x
exit /b 0
)
)
) else (
if defined value (1>>"%inifile%.1" echo(!line!)
echo(!line! | find /i "[%section%]" >NUL && set found=1
)
)
)
if exist "%inifile%.1" move /y "%inifile%.1" "%inifile%">NUL
例子
内容example.ini
:
[SectionName]
; This is a comment.
total=4
[AnotherSectionName]
# This is another comment.
total=7
[OtherSectionName]
And it should work with non-standard comments as well.
total=12
测试环节:
C:\Users\me\Desktop>ini /s AnotherSectionName /i total example.ini
7
C:\Users\me\Desktop>ini /s othersectionname /i Total /v f00 example.ini
f00
C:\Users\me\Desktop>type example.ini
[SectionName]
; This is a comment.
total=4
[AnotherSectionName]
# This is another comment.
total=7
[OtherSectionName]
And it should work with non-standard comments as well.
Total=f00
显然,纯批处理解决方案遇到像&
(可能%
还有其他)这样的字符时会窒息。所以这里有一个更强大的批处理 + JScript 混合脚本来解决这个问题。语法和输出相同(但添加/d
了删除item=value
对的开关)。
此脚本设置%ERRORLEVEL%=0
为成功和%ERRORLEVEL%=1
错误。
@if (@a==@b) @end /* -- batch / JScript hybrid line to begin JScript comment
:: --------------------
:: ini.bat
:: ini.bat /? for usage
:: --------------------
@echo off
setlocal enabledelayedexpansion
goto begin
:: color code by jeb -- https://stackoverflow.com/a/5344911/1683264
:c
set "param=^%~2" !
set "param=!param:"=\"!"
findstr /p /A:%1 "." "!param!\..\X" nul
<nul set /p ".=%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%"
exit /b
:: but it doesn't handle slashes. :(
:s
<NUL set /p "=/"&exit /b
:usage
for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do set "DEL=%%a"
<nul > X set /p ".=."
echo Usage:
call :c 07 " query:"
call :c 0F " %~nx0 "&call :s&call :c 0F "i item ["&call :s&call :c 0F "s section] inifile"&echo;
call :c 07 " create or modify:"
call :c 0F " %~nx0 "&call :s&call :c 0F "i item "&call :s&call :c 0F "v value ["&call :s&call :c 0F "s section] inifile"&echo;
call :c 07 " delete:"
call :c 0F " %~nx0 "&call :s&call :c 0F "d item ["&call :s&call :c 0F "s section] inifile"&echo;
echo;
echo Take the following ini file for example:
echo;
echo [Config]
echo password=1234
echo usertries=0
echo allowterminate=0
echo;
echo To read the "password" value:
call :c 0F " %~nx0 "&call :s&call :c 0F "s Config "&call :s&call :c 0F "i password inifile"&echo;
echo;
echo To modify the "usertries" value to 5:
call :c 0F " %~nx0 "&call :s&call :c 0F "s Config "&call :s&call :c 0F "i usertries "&call :s&call :c 0F "v 5 inifile"&echo;
echo;
echo To add a "timestamp" key with a value of the current date and time:
call :c 0F " %~nx0 "&call :s&call :c 0F "s Config "&call :s&call :c 0F "i timestamp "&call :s&call :c 0F "v ""%DEL%%%%%date%%%% %%%%time%%%%""%DEL% inifile"&echo;
echo;
echo To delete the "allowterminate" key:
call :c 0F " %~nx0 "&call :s&call :c 0F "s Config "&call :s&call :c 0F "d allowterminate inifile"&echo;
echo;
call :c 07 "In the above examples, "&call :s
call :c 0F "s Config "
echo is optional, but will allow the selection of
echo a specific item where the ini file contains similar items in multiple sections.
del X
goto :EOF
:begin
if "%~1"=="" goto usage
for %%I in (item value section found) do set %%I=
for %%I in (%*) do (
if defined next (
if !next!==/i set "item=%%~I"
if !next!==/v (
set modify=true
set "value=%%~I"
)
if !next!==/d (
set "item=%%~I"
set modify=true
set delete=true
)
if !next!==/s set "section=%%~I"
set next=
) else (
for %%x in (/i /v /s /d) do if "%%~I"=="%%x" set "next=%%~I"
if not defined next (
set "arg=%%~I"
if "!arg:~0,1!"=="/" (
1>&2 echo Error: Unrecognized option "%%~I"
1>&2 echo;
1>&2 call :usage
exit /b 1
) else set "inifile=%%~I"
)
)
)
for %%I in (item inifile) do if not defined %%I goto usage
if not exist "%inifile%" (
1>&2 echo Error: %inifile% not found.
exit /b 1
)
cscript /nologo /e:jscript "%~f0" "%inifile%" "!section!" "!item!" "!value!" "%modify%" "%delete%"
exit /b %ERRORLEVEL%
:: Begin JScript portion */
var inifile = WSH.Arguments(0),
section = WSH.Arguments(1),
item = WSH.Arguments(2),
value = WSH.Arguments(3),
modify = WSH.Arguments(4),
del = WSH.Arguments(5),
fso = new ActiveXObject("Scripting.FileSystemObject"),
stream = fso.OpenTextFile(inifile, 1),
// (stream.ReadAll() will not preserve blank lines.)
data = [];
while (!stream.atEndOfStream) { data.push(stream.ReadLine()); }
stream.Close();
// trims whitespace from edges
String.prototype.trim = function() { return this.replace(/^\s+|\s+$/,'') }
// trim + toLowerCase
String.prototype.unify = function() { return this.trim().toLowerCase(); };
// unquotes each side of "var"="value"
String.prototype.splitEx = function(x) {
for (var i=0, ret = this.split(x) || []; i<ret.length; i++) {
ret[i] = ret[i].replace(/^['"](.*)['"]$/, function(m,$1){return $1});
};
return ret;
}
// splices a new element into an array just after the last non-empty element. If first arg is a number, start at that position and look backwards.
Array.prototype.cram = function() {
for (var args=[], i=0; i<arguments.length; i++) { args.push(arguments[i]); }
var i = (typeof args[0] == "number" && Math.floor(args[0]) == args[0]) ? args.shift() : this.length;
while (i>0 && !this[--i].length) {};
for (var j=0; j<args.length; j++) this.splice(++i, 0, args[j]);
}
function saveAndQuit() {
while (data && !data[data.length - 1].length) data.pop();
var stream = fso.OpenTextFile(inifile, 2, true);
stream.Write(data.join('\r\n') + '\r\n');
stream.Close();
WSH.Quit(0);
}
function fatal(err) {
WSH.StdErr.WriteLine(err);
WSH.Quit(1);
}
if (section && !/^\[.+\]$/.test(section)) section = '[' + section + ']';
if (modify) {
if (section) {
for (var i=0; i<data.length; i++) {
if (data[i].unify() == section.unify()) {
for (var j=i + 1; j<data.length; j++) {
if (/^\s*\[.+\]\s*$/.test(data[j])) break;
var keyval = data[j].splitEx('=');
if (keyval.length < 2) continue;
var key = keyval.shift(), val = keyval.join('=');
if (key.unify() == item.unify()) {
if (del) data.splice(j, 1);
else {
data[j] = item + '=' + value;
WSH.Echo(value.trim());
}
saveAndQuit();
}
}
if (del) fatal(item + ' not found in ' + section + ' in ' + inifile);
data.cram(j ,item + '=' + value);
WSH.Echo(value.trim());
saveAndQuit();
}
}
if (del) fatal(section + ' not found in ' + inifile);
data.cram('\r\n' + section, item + '=' + value);
WSH.Echo(value.trim());
saveAndQuit();
}
else { // if (!section)
for (var i=0; i<data.length; i++) {
var keyval = data[i].splitEx('=');
if (keyval.length < 2) continue;
var key = keyval.shift(), val = keyval.join('=');
if (key.unify() == item.unify()) {
if (del) data.splice(i, 1);
else {
data[i] = item + '=' + value;
WSH.Echo(value.trim());
}
saveAndQuit();
}
}
if (del) fatal(item + ' not found in ' + inifile);
data.cram(item + '=' + value);
WSH.Echo(value.trim());
saveAndQuit();
}
}
else if (section) { // and if (!modify)
for (var i=0; i<data.length; i++) {
if (data[i].unify() == section.unify()) {
for (var j=i + 1; j<data.length; j++) {
if (/^\s*\[.+\]\s*$/.test(data[j])) fatal(item + ' not found in ' + section + ' in ' + inifile);
var keyval = data[j].splitEx('=');
if (keyval.length < 2) continue;
var key = keyval.shift(), val = keyval.join('=');
if (key.unify() == item.unify()) {
WSH.Echo(val.trim());
WSH.Quit(0);
}
}
}
}
fatal(section + ' not found in ' + inifile);
}
else { // if (item) and nothing else
for (var i=0; i<data.length; i++) {
var keyval = data[i].splitEx('=');
if (keyval.length < 2) continue;
var key = keyval.shift(), val = keyval.join('=');
if (key.unify() == item.unify()) {
WSH.Echo(val.trim());
WSH.Quit(0);
}
}
fatal(item + ' not found in ' + inifile);
}
我有一个简短的建议,即从 Windows 批处理(.bat)的当前目录中读取 config.ini 文件:
在批处理文件的末尾,我们粘贴该代码:
:ini
@for /f "tokens=2 delims==" %%a in ('find "%~2=" "%~1"') do @set %~3=%%a
@goto:eof
在批处理文件的开头附近,我们将其称为:
@call:ini "config.ini" IniFieldName batchVarName
@echo IniFieldName is: %batchVarName%
配置文件
foo=string
bar=123
baz=spaces work too!
windows_batch.cmd
for /F "tokens=*" %%I in (config.ini) do set %%I
老问题,但我最近才需要它并找到@paxdiablo 答案。我需要更多的东西,所以我丰富了他的答案,现在我正在回馈。
我还需要找到哪个键具有特定值。此外,明确支持根部分(没有部分名称)。
这是我的代码,一个我放入库中的函数(CMDLib 变量),我在需要时调用它(以及其他函数)。
:ReadINI
REM ReadINI - Get value from [Section]; Key from an INI File.
REM Arguments:
REM File INI-file to read from
REM Key Name of the entry
REM Section Name of the [Section] under which the Value is.
REM Optional, will find a value from the root section if empty.
REM For root section, set to "-" to also use "Value"
REM Value If Key is set to "-", will find which Key has "Value"
REM
REM Returns: A string of text will be echoed, ready for logging.
REM An echo of the value.
REM
REM Call example:
REM for /f "delims=" %%a in ('Call "%CMDLib%" ReadINI "Inifile" Key Section') do ( set Value=%%a)
REM
REM Original: http://stackoverflow.com/a/2866328/151152
rem ------- Function header -------
Setlocal ENABLEDELAYEDEXPANSION
:: Logging formatting
if not defined nest (set /a nest=0) else set /a Nest=%nest%+1
if %nest% GEQ 1 if not defined _tab (set _tab= ) else for /l %%i in (0, %nest%,1) do set _tab=%_tab%
rem ------- Function body -------
set file=%~1
set key=%~2
set Section=[%~3]
if "%Section%"=="-" set Section=
set value=%~4
set currSection=
Set RC=0
for /f "usebackq delims=" %%a in ("%file%") do (
set ln=%%a
if "x!ln:~0,1!"=="x[" (
set currSection=!ln!
) else (
for /f "tokens=1,2 delims==" %%b in ("!ln!") do (
set currkey=%%b
set currval=%%c
if /i "x!Section!"=="x!currSection!" (
if /i "x!key!"=="x!currkey!" (
echo !currval!
if %_D% GEQ 2 echo %_tab%[%0 - RC:%RC%]
exit /b %RC%
) Else if "x!key!"=="x-" (
if /i "x!value!"=="x!currval!" (
echo !currkey!
if %_D% GEQ 2 echo %_tab%[%0 - RC:%RC%]
exit /b %RC%
)
)
)
)
)
)
if %_D% GEQ 2 echo %_tab%[%0 - RC:%RC%]
Exit /b %RC%
rem ------- Function end -------
CMD 没有语法高亮显示?真可惜.. ;-)
希望这对其他人也有帮助。
嗯,也许这对某人有帮助.. 不得不构建它,因为 inifile.exe 用尽了技巧,并且似乎网络上的每个该死的 ini 解析器都需要“KEY”,而我只需要 [section] 下的所有值。所以,这里的部分打印..
@echo off
SETLOCAL DisableDelayedExpansion
IF "%1"=="" (echo Usage: section input.ext output.ext & goto eof )
IF "%2"=="" (echo Usage: section input.ext output.ext & goto eof )
IF NOT EXIST "%2" (echo File does not exist. Usage: section input.ext output.ext & goto eof )
IF "%3"=="" (echo Usage: section input.ext output.ext & goto eof )
FOR /F "tokens=*" %%A IN ('findstr /I /N "\[.*\]" %2') DO (echo %%A>>LINE_START.DAT)
FOR /F "tokens=1,2 delims=:" %%A IN ('findstr /I "\[%1\]" LINE_START.DAT') DO (
SETLOCAL EnableDelayedExpansion
set FIRSTLINE=%%A
)
set /a "FIRSTLINE+=1"
FOR /F "tokens=1,2* delims=:" %%A IN ('findstr /I /N ".*" %2') DO (
IF %%A GEQ !FIRSTLINE! (echo %%B>>LINE_END.DAT)
)
set ENDLINE=500
FOR /F "tokens=1,2* delims=:" %%A IN ('findstr /I /N "\[.*\]" LINE_END.DAT') DO (
IF %%A LSS !ENDLINE! (set /a "ENDLINE=%%A") ELSE echo %%A>nul
)
set /a "ENDLINE-=1"
FOR /F "tokens=1,2* delims=:" %%A IN ('findstr /I /N ".*" LINE_END.DAT') DO (
IF %%A LEQ !ENDLINE! (echo %%B>>%3) ELSE ENDLOCAL
)
set ENDLINE=0
set FIRSTLINE=0
ENDLOCAL
DEL /Q LINE_*.DAT
:end
是的,是的,我知道它看起来像是来自后面,但它确实有效,但不确定它是否适用于文件夹中的空格或文件中的空格。将其构建为基本上只有 .ini 文件位于同一文件夹并从命令行运行。
用法:genetix_ini.cmd 部分 input.ext output.ext
更新#2:似乎,我在没有将 2 个集合变量归零时犯了错误。这开始在脚本的第二遍引起问题。
再次感谢这个出色的 INI 脚本和 2017 年 5 月 23 日发布的更新。仍然非常有用!
我确实添加了一个 /q开关来“保持安静”,从而抑制了由 fatal() 函数发出的消息。这是必要的,因为我从 Windows CMD 脚本调用 INI 脚本,我发现 stdout (1>) 和 stderr (2>) 的重定向不会拦截 Windows 脚本主机发出的消息。
一个例子:
for /f "usebackq tokens=*" %%a in (`ini /s Section /i Entry File.ini`) do set go_drive=%%a 1> nul: 2> nul:
...不抑制错误消息,而...
for /f "usebackq tokens=*" %%a in (`ini /q /s Section /i Entry File.ini`) do set go_drive=%%a 1> nul: 2> nul:
...正在抑制错误消息
我已经发布了与此代码相邻的代码。
@if (@a==@b) @end /* -- batch / JScript hybrid line to begin JScript comment
:: ----------------------------------------------------------------------------------------------
:: ini.bat
:: ini.bat /? for usage
::
:: Source: https://stackoverflow.com/questions/2866117/windows-batch-script-to-read-an-ini-file
::
:: 2021-08-03: /q switch added, to suppress error messages
::
:: ----------------------------------------------------------------------------------------------
@echo off
setlocal enabledelayedexpansion
goto begin
:: color code by jeb -- https://stackoverflow.com/a/5344911/1683264
:c
set "param=^%~2" !
set "param=!param:"=\"!"
findstr /p /A:%1 "." "!param!\..\X" nul
<nul set /p ".=%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%"
exit /b
:: but it doesn't handle slashes. :(
:s
<NUL set /p "=/"&exit /b
:usage
for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do set "DEL=%%a"
<nul > X set /p ".=."
echo Usage:
call :c 07 " query:"
call :c 0F " %~nx0 "&call :s&call :c 0F "i item ["&call :s&call :c 0F "s section] inifile"&echo;
call :c 07 " create or modify:"
call :c 0F " %~nx0 "&call :s&call :c 0F "i item "&call :s&call :c 0F "v value ["&call :s&call :c 0F "s section] inifile"&echo;
call :c 07 " delete:"
call :c 0F " %~nx0 "&call :s&call :c 0F "d item ["&call :s&call :c 0F "s section] inifile"&echo;
call :c 07 " quiet:"
call :c 0F " %~nx0 "&call :s&call :c 0F "q "&echo;
echo;
echo Take the following ini file for example:
echo;
echo [Config]
echo password=1234
echo usertries=0
echo allowterminate=0
echo;
echo To read the "password" value:
call :c 0F " %~nx0 "&call :s&call :c 0F "s Config "&call :s&call :c 0F "i password inifile"&echo;
echo;
echo To modify the "usertries" value to 5:
call :c 0F " %~nx0 "&call :s&call :c 0F "s Config "&call :s&call :c 0F "i usertries "&call :s&call :c 0F "v 5 inifile"&echo;
echo;
echo To add a "timestamp" key with a value of the current date and time:
call :c 0F " %~nx0 "&call :s&call :c 0F "s Config "&call :s&call :c 0F "i timestamp "&call :s&call :c 0F "v ""%DEL%%%%%date%%%% %%%%time%%%%""%DEL% inifile"&echo;
echo;
echo To delete the "allowterminate" key:
call :c 0F " %~nx0 "&call :s&call :c 0F "s Config "&call :s&call :c 0F "d allowterminate inifile"&echo;
echo;
call :c 07 "In the above examples, "&call :s
call :c 0F "s Config "
echo is optional, but will allow the selection of
echo a specific item where the ini file contains similar items in multiple sections.
del X
goto :EOF
:begin
if "%~1"=="" goto usage
for %%I in (item value section found) do set %%I=
for %%I in (%*) do (
if defined next (
if !next!==/i set "item=%%~I"
if !next!==/v (
set modify=true
set "value=%%~I"
)
if !next!==/d (
set "item=%%~I"
set modify=true
set delete=true
)
if !next!==/s set "section=%%~I"
:
: /q switch added. Suppress error messages.
:
if !next!==/q set quiet=true
set next=
) else (
for %%x in (/i /v /s /d /q) do if "%%~I"=="%%x" set "next=%%~I"
if not defined next (
set "arg=%%~I"
if "!arg:~0,1!"=="/" (
1>&2 echo Error: Unrecognized option "%%~I"
1>&2 echo;
1>&2 call :usage
exit /b 1
) else set "inifile=%%~I"
)
)
)
for %%I in (item inifile) do if not defined %%I goto usage
if not exist "%inifile%" (
1>&2 echo Error: %inifile% not found.
exit /b 1
)
cscript /nologo /e:jscript "%~f0" "%inifile%" "!section!" "!item!" "!value!" "%modify%" "%delete%" "%quiet%"
exit /b %ERRORLEVEL%
:: Begin JScript portion */
var inifile = WSH.Arguments(0),
section = WSH.Arguments(1),
item = WSH.Arguments(2),
value = WSH.Arguments(3),
modify = WSH.Arguments(4),
del = WSH.Arguments(5),
quiet = WSH.Arguments(6),
fso = new ActiveXObject("Scripting.FileSystemObject"),
stream = fso.OpenTextFile(inifile, 1),
// (stream.ReadAll() will not preserve blank lines.)
data = [];
while (!stream.atEndOfStream) { data.push(stream.ReadLine()); }
stream.Close();
// trims whitespace from edges
String.prototype.trim = function() { return this.replace(/^\s+|\s+$/,'') }
// trim + toLowerCase
String.prototype.unify = function() { return this.trim().toLowerCase(); };
// unquotes each side of "var"="value"
String.prototype.splitEx = function(x) {
for (var i=0, ret = this.split(x) || []; i<ret.length; i++) {
ret[i] = ret[i].replace(/^['"](.*)['"]$/, function(m,$1){return $1});
};
return ret;
}
// splices a new element into an array just after the last non-empty element. If first arg is a number, start at that position and look backwards.
Array.prototype.cram = function() {
for (var args=[], i=0; i<arguments.length; i++) { args.push(arguments[i]); }
var i = (typeof args[0] == "number" && Math.floor(args[0]) == args[0]) ? args.shift() : this.length;
while (i>0 && !this[--i].length) {};
for (var j=0; j<args.length; j++) this.splice(++i, 0, args[j]);
}
function saveAndQuit() {
while (data && !data[data.length - 1].length) data.pop();
var stream = fso.OpenTextFile(inifile, 2, true);
stream.Write(data.join('\r\n') + '\r\n');
stream.Close();
WSH.Quit(0);
}
function fatal(err) {
if (!quiet) {
WSH.StdErr.WriteLine(err);
}
WSH.Quit(1);
}
if (section && !/^\[.+\]$/.test(section)) section = '[' + section + ']';
if (modify) {
if (section) {
for (var i=0; i<data.length; i++) {
if (data[i].unify() == section.unify()) {
for (var j=i + 1; j<data.length; j++) {
if (/^\s*\[.+\]\s*$/.test(data[j])) break;
var keyval = data[j].splitEx('=');
if (keyval.length < 2) continue;
var key = keyval.shift(), val = keyval.join('=');
if (key.unify() == item.unify()) {
if (del) data.splice(j, 1);
else {
data[j] = item + '=' + value;
WSH.Echo(value.trim());
}
saveAndQuit();
}
}
if (del) fatal(item + ' not found in ' + section + ' in ' + inifile);
data.cram(j ,item + '=' + value);
WSH.Echo(value.trim());
saveAndQuit();
}
}
if (del) fatal(section + ' not found in ' + inifile);
data.cram('\r\n' + section, item + '=' + value);
WSH.Echo(value.trim());
saveAndQuit();
}
else { // if (!section)
for (var i=0; i<data.length; i++) {
var keyval = data[i].splitEx('=');
if (keyval.length < 2) continue;
var key = keyval.shift(), val = keyval.join('=');
if (key.unify() == item.unify()) {
if (del) data.splice(i, 1);
else {
data[i] = item + '=' + value;
WSH.Echo(value.trim());
}
saveAndQuit();
}
}
if (del) fatal(item + ' not found in ' + inifile);
data.cram(item + '=' + value);
WSH.Echo(value.trim());
saveAndQuit();
}
}
else if (section) { // and if (!modify)
for (var i=0; i<data.length; i++) {
if (data[i].unify() == section.unify()) {
for (var j=i + 1; j<data.length; j++) {
if (/^\s*\[.+\]\s*$/.test(data[j])) fatal(item + ' not found in ' + section + ' in ' + inifile);
var keyval = data[j].splitEx('=');
if (keyval.length < 2) continue;
var key = keyval.shift(), val = keyval.join('=');
if (key.unify() == item.unify()) {
WSH.Echo(val.trim());
WSH.Quit(0);
}
}
}
}
fatal(section + ' not found in ' + inifile);
}
else { // if (item) and nothing else
for (var i=0; i<data.length; i++) {
var keyval = data[i].splitEx('=');
if (keyval.length < 2) continue;
var key = keyval.shift(), val = keyval.join('=');
if (key.unify() == item.unify()) {
WSH.Echo(val.trim());
WSH.Quit(0);
}
}
fatal(item + ' not found in ' + inifile);
}