!BAT
:: GRUB4DOS batch script. See Tutorial at www.easy2boot.com [SSi]
:: Uses: Adds payload and *.mnu file contents to make a single menu (.txt . and .cmd files are ignored)
:: Usage:  \grub\AUTOMN.g4b .automenu (folder that has .mnu files)
::        then load using configfile     (md)0x3000+0x50
:: Path is %2 variable - e.g. /_ISO/MAINMENU
:: A configfile is generated by this code for all payload\mnu files in the /%2 folder and below
:: e.g.
:: \grub\AUTOMN.g4d .automenu /_ISO
:: Configfile (md)0x3000+0x50
::
:: This script requires GRUB4DOS 2010-12-14 or later.
:: version 3 increase memory from 0x3000+0x10 to 0x3000+0x50
:: version 4  31 May 2013 - allow %2 to have device specified - e.g. (hdx,y)/zzz or (bd)/zz else use ()
:: version 5  21 June 2012 - sort payload files alphabetically
:: version 6 16 Aug 2013 - bugfix MFOLDER started with () now starts with just /
:: version 7 11 Sep 2013 - check for no 'title' keyword in .txt file
:: version 8 9 Dec 2013 - use .hdr files
:: version 9 29 Jan 2104 - add $HOME$ detection (:XLATE code)
:: version 10 3 Mar 2014 - convert $HOME$ in .txt file to current folder
:: version 11 27 Apr 2014 - bugfix for Modulo 4GB files not working with cat --length=0
:: version 12 13 May 2014 - bugfix for v11 - errorcheck must be off or cat --length=0 on dir fails if FAT32 (only happened if folder had a . in name)
:: version 13 31 July 2014 - speed improvements to minimise USB disk access
:: version 14 31 Jan 2015 - reload main menu on failure of boot
::=============================================================================

::set DD=0
::Uncomment line below to show debug lines
::set DD=1

debug off
checkrange 20130710:-1 read 0x8278 || pause Error - Old grub4dos version: Please use grldr from the E2B download! && set badver=1
:: this batch file calls itself, so use the label as the place to jump to
goto %~x1
exit


:.automenu

:: must turn off errorcheck or FAT32 dirs give error if using cat --length=0
errorcheck off

:: Variables: %0=/xxx/automenu.bat %~nx0=automenu.bat %~nx1=.automenu %1=.automenu %~x1=.automenu
::echo 0=%0 nx0=%~nx0 nx1=%~nx1 nx2=%~nx2 nx3=%~nx3 1=%1 x1=%~x1
:: get the menu folder into DIR variable
::echo Checking if .makemenu is loaded - if not load it
::delmod -l %~nx0 || insmod %0 .makemenu
if not "%MOD%"=="1" delmod -l %~nx0 || insmod %0

if "%STARTMENU%"=="NONE" goto :notnew
if "%DD%"=="1" echo Writing default menu entry
if "%DD%"=="1" echo -e default 0\n#timeout 10\n\n > (md)0x3000+0x50
if "%STARTMENU%"=="" set STARTMENU=%grub%/MNU.hdr
#if exist (bd)/%STARTMENU% echo Using default user menu %STARTMENU%  %redir%
#cat --length=0 (bd)/%STARTMENU% > nul && cat (bd)/%STARTMENU% > (md)0x3000+0x50
cat (bd)/%STARTMENU% > (md)0x3000+0x50

::set ME=%0
:notnew

if "%2"=="" goto :endloop
set DIR=%2

if not "%DIR:~0,1%"=="(" set DIR=()%DIR%
::echo Using %2 as main folder for source and .mnu  files - bugfix 16-08-2013
echo set MFOLDER=%2 >> (md)0x3000+0x50

# set variable to show we are in top level folder
set TOP=1
#echo AUTOMN.g4b: Searching %DIR% %redir%
ls %DIR%/ | call :cpa

echo %redir%
::echo @AUTOMN FINISHED LS of %DIR% && pause

:endloop
::echo writing back to main menu entry

if not "%LBACKMENU%"=="" if not exist NOF7HD set MDIR=(bd)/%grub%/MenuF7.hdr && call :XLATE
if not "%LBACKMENU%"=="" if not exist NOF8B  set MDIR=(bd)/%grub%/MenuF8.hdr && call :XLATE
if "%NOF9R%"==""                             set MDIR=(bd)/%grub%/MenuF9.hdr && call :XLATE
if "%NOF10H%"==""                            set MDIR=(bd)/%grub%/MenuF10.hdr && call :XLATE

set DD=
set DIR=
:: must set root back!
root (bd)/

if "%EBACKUP%"=="YES" echo BACKING UP TO /%grub%/BACKUP.lst...
if "%EBACKUP%"=="YES" cat (md)0x3000+0x50 > (bd)/%grub%/BACKUP.lst
if "%EBACKUP%"=="YES" pause
delmod %~nx0 > nul

set emsg=
set emsgcol=
set TOP=
set MDIR=
set mem=
set mem1=
set s=
set count=
debug 1

exit

:: ----------------------- SUBROUTINES ----------------------


:.addpay

if "%DD%"=="1" echo @ADDPAY
setlocal && set NOSORT=%NOSORT%
#turn on echo for cat command
debug 1
if "%DD%"=="1" echo ADDPAY: Checking %DIR%/%1 
if "%1"=="" endlocal && goto :EOF
#If is a directory ignore it
cat --length=0 %DIR%/%1 > (md)0x220+1
#If length does not start 0x then is FAT32 dir and got an error!
cat --locate="is 0x" (md)0x220+1 > nul || goto :EOF
#if 0 length file or dir then ignore
cat --locate="is 0x0" (md)0x220+1 > nul && goto :EOF

:: if not iso file then ignore
if "%DD%"=="1" echo AUTOMN: checking %~x1 extension 

if /i "#.txt#"=="#%~x1#" goto :eof
if /i "#.cmd#"=="#%~x1#" goto :eof
if /i "#.mnu#"=="#%~x1#" goto :eof
if "#.#"=="#%~x1#" goto :eof

set LL=0
cat --length=0 %DIR%/%~n1.txt > nul && set LL=1
if "%LL%"=="1" && cat --length=9 --locate="title " %DIR%/%~n1.txt > nul || echo -e $[0104]ERROR: No 'title' keyword in %~n1.txt! && set LL=0 && pause
if "%LL%"=="0" echo -e Adding %DIR%/%1 %redir% 
if "%LL%"=="1" echo -e Adding %DIR%/%1 and menu title from %~n1.txt %redir%

echo %~x1 > (md)0x220+1
set B64=
cat --locate=64 (md)0x220+1 > nul && set B64=1
set xx=%~x1
echo %xx:~-2% > (md)0x220+1
set xx=
cat --locate=32 (md)0x220+1 > nul && set B64=32
if "%B64%"=="" if not exist EXTOFF if "%LL%"=="0" echo title %1\n %DIR%/%1 >> (md)0x3000+0x50
if "%B64%"=="" if exist EXTOFF if "%LL%"=="0" echo title %~n1\n %DIR%/%1 >> (md)0x3000+0x50
if "%B64%"=="1" if not exist EXTOFF if "%LL%"=="0" echo iftitle [checkrange 2,3 is64bit] %1\n %DIR%/%1 >> (md)0x3000+0x50
if "%B64%"=="1" if exist EXTOFF if "%LL%"=="0" echo iftitle [checkrange 2,3 is64bit] %~n1\n %DIR%/%1 >> (md)0x3000+0x50
if "%B64%"=="32" if not exist EXTOFF if "%LL%"=="0" echo iftitle [checkrange 0,1 is64bit] %1\n %DIR%/%1 >> (md)0x3000+0x50
if "%B64%"=="32" if exist EXTOFF if "%LL%"=="0" echo iftitle [checkrange 0,1 is64bit] %~n1\n %DIR%/%1 >> (md)0x3000+0x50
set B64=
:: if "%LL%"=="1" cat %DIR%/%~n1.txt >> (md)0x3000+0x50
if "%LL%"=="1" set MDIR=%DIR%/%~n1.txt && call :XLATE

echo >> (md)0x3000+0x50
echo ()/%grub%/QRUN.g4b %DIR%/%1 >> (md)0x3000+0x50
echo -e errorcheck off\nboot\nerrorcheck on\nconfigfile (md)0xa000+0x50 >> (md)0x3000+0x50
goto :EOF


:.addmnu
if "%DD%"=="1" echo @MAKEMENU
setlocal  && set NOSORT=%NOSORT%
if "%DD%"=="1" echo Checking %DIR%/%1
if "%1"=="" endlocal && goto :EOF

::If is a directory ignore it
::cat --length=0 (bd)%DIR%/%1 || goto :EOF

:: if not mnu file then ignore
if "%DD%"=="1" echo MAKEMENU: checking %~x1 extension 
if /i not "#.mnu#"=="#%~x1#" goto :EOF

echo -e Adding %DIR%/%1 %redir%
:: e.g. %DIR% = ()/_ISO/MAINMENU/MNU
set LL=0
set MDIR=%DIR%/%1 
goto :XLATE


:XLATE
set DDIR=%DIR%
:: get rid of leading ()
if "%DDIR:~0,2%"=="()" set DDIR=%DDIR:~2%
if "%DD%"=="1" echo Changing all $HOME$ strings in file %MDIR% to %DDIR%
echo > (md)0x3100+0x20
set ST=0
set END=0
:: For faster speed copy .mnu file to memory  A800 = 21MB address
cat %MDIR% > (md)0xA800+0x100
set MDIR=(md)0xA800+0x100

:XLOOP
if "%DD%"=="1" echo Start=%ST%
cat --skip=%ST% --locate=$HOME$ --number=1 %MDIR% > nul
set /a END=%?% > nul
if  "%END%"=="0" goto :nohome
set /a LENGTH=%END%-%ST% > nul
cat --skip=%ST% --length=%LENGTH% %MDIR% >> (md)0x3100+0x20
echo -n %DDIR% >> (md)0x3100+0x20
set /a ST=%END%+6 > nul
goto :XLOOP

:nohome
cat --skip=%ST% %MDIR% >> (md)0x3100+0x20
echo >> (md)0x3100+0x20
:: copy and convert $$STR keywords into menu at (md)0x3100+0x20
call :XLATE9
set DD=
set LENGTH=
set END=
set ST=
set DDIR=
set mem=
set mem1=
set s=
goto :EOF

::-----------------------

:: -- $$STR substitution

:XLATE9
set MDIR=(md)0x3100+0x20
if "%DD%"=="1" echo Changing all $$STR strings in file %MDIR%
echo -n > (md)0x3300+0x20
set ST=0
set END=0

:XLOOP9
if "%DD%"=="1" echo Looking for $$STR starting at %ST%
cat --skip=%ST% --locate="$$STR" --number=1 %MDIR% > nul
set /a END=%?% > nul
if  "%END%"=="0" goto :nohome9
set /a LENGTH=%END%-%ST% > nul
cat --skip=%ST% --length=%LENGTH% %MDIR% >> (md)0x3300+0x20
cat --skip=%END% --length=9 %MDIR% | echo -e !BAT\nset A= > (md)0x3200+1
call (md)0x3200+1
if "%DD%"=="1" echo Found %A%

:: now find A in (md)0x880+0x80
cat --locate=%A% --number=1 (md)0x880+0x80 > nul
set /a ALOC=%?% > nul
if "%ALOC%"=="0" echo $[0104]ERROR %A% NOT FOUND IN STRINGS.TXT FILE! && pause
if "%ALOC%"=="0" echo -n %A% >> (md)0x3300+1 && goto :badstr
set /a ALOC=%ALOC%+10 > nul
:: get end of line
cat --locate=\x0a --skip=%ALOC% --number=1 (md)0x880+0x80 > nul
set /a LL=%?%-%ALOC%-1 > nul
cat --skip=%ALOC% --length=%LL% (md)0x880+0x80 >> (md)0x3300+0x20
if "%DD%"=="1" echo Replacing with
if "%DD%"=="1" cat --skip=%ALOC% --length=%LL% (md)0x880+0x80 && echo 
set A=
set ALOC=
set LL=

:badstr
# move past string and CR\LF
set /a ST=%END%+9 > nul
goto :XLOOP9

:nohome9
if "%DD%"=="1" echo NOHOME9
cat --skip=%ST% %MDIR% >> (md)0x3300+0x20
echo -n >> (md)0x3300+0x20
:: copy to menu at 0x3000
cat (md)0x3300+0x20 >> (md)0x3000+0x50
set ALOC=
set LL=
set LENGTH=
set END=
set ST=
set DDIR=
goto :EOF

:: ----

:cpa
::echo @CPA: Current Root: %DIR%
::echo Change source root to %DIR%
:: must or || in case empty directory! Prevents hanging if use root without dir access!

::echo -n AUTOMN: Enumerating files in %DIR% %redir%
ls %DIR%/ > nul || echo -n  > nul
root %DIR%/ > nul || goto :eof
if exist NOSORT && ls | call :copyfiles && goto :eof
if exist DD echo AUTOMN: Sorting files %@time%
::echo -e and sorting files... %redir%
:: get dir listing and sort entries alphabetically
set sortlist=(md)0x1c000+0x50
echo -e -n \x00\x00 > %sortlist%
ls | call :sort 
cat %sortlist% | call :copyfiles 
set sortlist=
goto :eof

:: ---------------------

:copyfiles
::echo @COPYFILES @%1@
if "%1"=="" goto :eof
::If is a directory
::cat --length=0 /%1 || goto :sub-dir
if "##"=="#%~x1#" goto :sub-dir

:: Show new directory
if not "%DIR%"=="%LASTDIR%" set LASTDIR=%DIR% && echo -e %DIR% %redir%
if "%TOP%"=="1" if not "#.mnu#"=="#%~x1#" call :.addpay %1
if "#.mnu#"=="#%~x1#" call :.addmnu %1
shift
goto :copyfiles


:sub-dir
setlocal
set TOP=0
set DIR=%DIR%/%1
call :cpa
endlocal
shift
goto :copyfiles

:: ------------ SORT LIST -----

:sort
set /a count=0 > nul
echo -e \x00\x00 > %sortlist%
if "%1"=="" goto :eof
set mem=0x23450
:loop
if "%1"=="" goto :startSort
if "#%~x1#"=="#.txt#" shift && goto :loop
set s=%1
set /A mem1=%mem%+%count% > nul
echo %1 > (md)%mem1%+1
set /A count=%count%+1 > nul
shift
goto loop

:startSort
::echo STARTSORT count=%count% && pause
if "%count%"=="0" exit
if "%count%"=="0x1" echo -n %s% > %sortlist%  &&  goto :eof
set /a total=%count%-1 > nul

:: Following code runs many times so make efficient!

:RestartSort
set count=0 > nul

:sortLoop
set /a next=%count%+1 > nul
call :swap %count% %next%
set /a count=%count%+1 > nul
if "%swapped%"=="1" goto :RestartSort
if "%count%"=="%total%" goto :output || goto :sortLoop

:swap
set /A mem1=%mem%+%1 > nul && set /A mem2=%mem%+%2 > nul
cat (md)%mem1%+1 | set var1= && cat (md)%mem2%+1 | set var2=
if "%badver%"=="1" if %var1%<=%var2% set swapped= && goto :eof
if "%badver%"=="" if /i %var1%<=%var2% set swapped= && goto :eof
echo %var1% > (md)%mem2%+1 && echo %var2% > (md)%mem1%+1
set swapped=1 && goto :eof

:output
set count=0
set /a total=%total%+1 > nul
:llp
if %count%>=%total% goto :tidyup
set /A mem1=%mem%+%count% > nul
cat (md)%mem1%+1 | set f=
echo -n %f% >> %sortlist%
echo -n -e \x20 >> %sortlist%
::| set %sortlist%=%sortlist% 
set /a count=%count%+1 > nul
goto :llp

:tidyup
set mem=
set mem1=
set mem2=
set var1=
set var2=
set count=
set swapped=
::cat %sortlist% && echo COUNT=%total% && pause
set total=
set f=
set s=
set next=




