I am trying to write a batch function, that takes a filename and an array name, copies every name from the file into array variables.
The function should, not skip empty lines, not cause error or mangle the line's text, not add extra text.
The function should not depend on delayedexpansion being set when called, and it should return with delayedexpansion in the same state as it was before (it should not return in a setlocal nest).
It should be possible to take any regular text file, call it into this function, and then run another function to copy the entire array back to a file, the input and output files should be internally identical as verified by a hash function
So far, my best go at making this function as as follows
Code: Select all
::Usage Call :SimpleFileToArray OutputArray Filename
:SimpleFileToArray
for /f delims^=^ eol^= %%a in ('%SystemRoot%\System32\findstr.exe /N "^" "%~2"') do (
for /f "tokens=1,2* delims=:" %%f in ("%%a") do set "%~1.ubound=%%f" & set %~1[%%f]=%%a
)
GoTo :EOF
Here is the launcher function
Code: Select all
:SimpleFileToArray-DEMO
Call :ClearVariablesByPrefix _FTA LinesArray
echo start SimpleFileToArray %time%
Call :SimpleFileToArray LinesArray batchsample.bat
echo end SimpleFileToArray %time%
GoTo :EOF
Code: Select all
:: Usage Call :ClearVariablesByPrefix myPrefix
:ClearVariablesByPrefix
if "[%~1]" NEQ "[]" for /f "tokens=1,2 delims==" %%a in ('set %~1 2^>nul') do set %%a=
if "[%~2]" NEQ "[]" shift & GoTo :ClearVariablesByPrefix
GoTo :EOF
It runs in about 1.5 seconds if the set array.ubound is omitted (but then you have to find the ubound, which takes more than 0.5 seconds to the best of my knowledge, it would be great to set ubound only once.)
But this function has one flaw, it leaves behind the line numbers in the string !
Example
Code: Select all
LinesArray[1052]=1052: if "[%_GSS_state%]" NEQ "[]" if "[%_GSS_message%]" NEQ "[]" set "powercfg.sleepstates[%_GSS_sleepstate_index%].unsupported=true"
LinesArray[1053]=1053: if "[%_GSS_state%]" NEQ "[]" if "[%_GSS_message%]" NEQ "[]" set "powercfg.sleepstates[%_GSS_sleepstate_index%]=%_GSS_state%"
LinesArray[1054]=1054: if "[%_GSS_state%]" NEQ "[]" if "[%_GSS_message%]" NEQ "[]" set "powercfg.sleepstates[%_GSS_sleepstate_index%].message=%_GSS_message%"
LinesArray[1055]=1055: if "[%_GSS_state%]" NEQ "[]" if "[%_GSS_message%]" NEQ "[]" set "powercfg.sleepstates.ubound=%_GSS_sleepstate_index%"
LinesArray[1056]=1056: if "[%_GSS_state%]" NEQ "[]" if "[%_GSS_message%]" NEQ "[]" set "powercfg.sleepstates.unsupported[%_GSS_unsupported_sleepstate_index%]=%_GSS_state%"
To try and remedy this, I have attempted the following version
Code: Select all
::Usage Call :SimpleFileToArray OutputArray Filename
:SimpleFileToArray
for /f delims^=^ eol^= %%a in ('%SystemRoot%\System32\findstr.exe /N "^" "%~2"') do (
for /f "tokens=1,2* delims=:" %%b in ("%%a") do (
setlocal enabledelayedexpansion
set _SFTA_buffer=%%a
set _SFTA_buffer=!_SFTA_buffer:*:=!
for /f "delims=" %%d in ('echo(!_SFTA_buffer!') do (
endlocal
set %~1.ubound=%%b
set %~1[%%b]=%%d
)
if defined _SFTA_buffer endlocal
)
)
GoTo :EOF
So I created a debug function to try and figure it out
Code: Select all
::Usage Call :SimpleFileToArray OutputArray Filename
:SimpleFileToArray
for /f delims^=^ eol^= %%a in ('%SystemRoot%\System32\findstr.exe /N "^" "%~2"') do (
for /f "tokens=1,2* delims=:" %%b in ("%%a") do (
echo ---NEWLINE---
echo(line number %%b
echo(0%%a
setlocal enabledelayedexpansion
set _SFTA_buffer=%%a
echo(1!_SFTA_buffer!
set _SFTA_buffer=!_SFTA_buffer:*:=!
echo(2!_SFTA_buffer!
for /f "delims=" %%d in ('echo(!_SFTA_buffer!') do (
endlocal
echo(line number %%b
echo(3%%d
set %~1.ubound=%%b
echo set %~1[%%b]=%%d
set %~1[%%b]=%%d
echo ---ENDLINE---
)
if defined _SFTA_buffer endlocal
)
)
GoTo :EOF
Code: Select all
---NEWLINE---
line number 1
01:@echo off
11:@echo off
2@echo off
line number 1
3@echo off
set LinesArray[1]=@echo off
---ENDLINE---
With @echo off here is that first loop
Code: Select all
D:\dev\work>Call :SimpleFileToArray LinesArray batchsample.bat
D:\dev\work>for /F delims= eol= %a in ('C:\Windows\System32\findstr.exe /N "^" "batchsample.bat"') do (for /F "tokens=1,2* delims=:" %b in ("%a") do (
echo ---NEWLINE---
echo(line number %b
echo(0%a
setlocal enabledelayedexpansion
set _SFTA_buffer=%a
echo(1!_SFTA_buffer!
set _SFTA_buffer=!_SFTA_buffer:*:=!
echo(2!_SFTA_buffer!
for /F "delims=" %d in ('echo(!_SFTA_buffer!') do (
endlocal
echo(line number %b
echo(3%d
set LinesArray.ubound=%b
echo set LinesArray[%b]=%d
set LinesArray[%b]=%d
echo ---ENDLINE---
)
if defined _SFTA_buffer endlocal
) )
D:\dev\work>(for /F "tokens=1,2* delims=:" %b in ("1:@echo off") do (
echo ---NEWLINE---
echo(line number %b
echo(01:@echo off
setlocal enabledelayedexpansion
set _SFTA_buffer=1:@echo off
echo(1!_SFTA_buffer!
set _SFTA_buffer=!_SFTA_buffer:*:=!
echo(2!_SFTA_buffer!
for /F "delims=" %d in ('echo(!_SFTA_buffer!') do (
endlocal
echo(line number %b
echo(3%d
set LinesArray.ubound=%b
echo set LinesArray[%b]=%d
set LinesArray[%b]=%d
echo ---ENDLINE---
)
if defined _SFTA_buffer endlocal
) )
D:\dev\work>(
echo ---NEWLINE---
echo(line number 1
echo(01:@echo off
setlocal enabledelayedexpansion
set _SFTA_buffer=1:@echo off
echo(1!_SFTA_buffer!
set _SFTA_buffer=!_SFTA_buffer:*:=!
echo(2!_SFTA_buffer!
for /F "delims=" %d in ('echo(!_SFTA_buffer!') do (
endlocal
echo(line number 1
echo(3
set LinesArray.ubound=1
echo set LinesArray[1]=
set LinesArray[1]=
echo ---ENDLINE---
)
if defined _SFTA_buffer endlocal
)
---NEWLINE---
line number 1
01:@echo off
11:@echo off
2@echo off
D:\dev\work>(
endlocal
echo(line number 1
echo(3@echo off
set LinesArray.ubound=1
echo set LinesArray[1]=@echo off
set LinesArray[1]=@echo off
echo ---ENDLINE---
)
line number 1
3@echo off
set LinesArray[1]=@echo off
---ENDLINE---
I have also asked poorly on reddit https://old.reddit.com/r/Batch/comments ... _an_array/