1echo Tests for cmd's builtin commands
2
3@echo on
4echo ------------ Testing 'echo' [ON] ------------
5echo word
6echo 'singlequotedword'
7echo "doublequotedword"
8@echo at-echoed-word
9echo "/?"
10echo.
11echo .
12echo.word
13echo .word
14echo:
15echo :
16echo:word
17echo :word
18echo/
19echo /
20echo/word
21echo /word
22echo off now
23echo word@space@
24echo word@space@@space@
25 echo word
26echo@tab@word
27echo@tab@word @tab@
28echo@tab@word@tab@@space@
29@tab@echo word
30echo @tab@word
31echo  @tab@word
32echo@tab@@tab@word
33echo @tab@ on @space@
34@echo --- @ with chains and brackets
35(echo the @ character chains until&&@echo we leave the current depth||(
36echo hidden
37@echo hidden
38))&&echo and can hide brackets||(@echo command hidden)||@(echo brackets hidden)
39@echo ---
40
41@echo off
42echo off@tab@@space@
43@echo noecho1
44 @echo noecho2
45@@@@@echo echo3
46echo ------------ Testing 'echo' [OFF] ------------
47echo word
48echo 'singlequotedword'
49echo "doublequotedword"
50@echo at-echoed-word
51echo "/?"
52echo.
53echo .
54echo.word
55echo .word
56echo:
57echo :
58echo:word
59echo :word
60echo/
61echo /
62echo/word
63echo /word
64echo on again
65echo word@space@
66echo word@space@@space@
67 echo word
68echo@tab@word
69echo@tab@word @tab@
70echo@tab@word@tab@@space@
71@tab@echo word
72echo @tab@word
73echo  @tab@word
74echo@tab@@tab@word
75
76echo ------------ Testing mixed echo modes ------------
77echo @echo on> mixedEchoModes.cmd
78echo if 1==1 echo foo>> mixedEchoModes.cmd
79echo if 1==1 @echo bar>> mixedEchoModes.cmd
80echo @echo off>> mixedEchoModes.cmd
81echo if 1==1 echo foo2>> mixedEchoModes.cmd
82echo if 1==1 @echo bar2>> mixedEchoModes.cmd
83type mixedEchoModes.cmd
84cmd /c mixedEchoModes.cmd
85del mixedEchoModes.cmd
86
87echo ------------ Testing parameterization ------------
88call :TestParm a b c
89call :TestParm "a b c"
90call :TestParm "a b"\c
91call :TestParm a=~`+,.{}!+b
92call :TestParm a;b
93call :TestParm "a;b"
94call :TestParm a^;b
95call :TestParm a[b]{c}(d)e
96call :TestParm a&echo second line
97call :TestParm a   b,,,c
98call :TestParm a==b;;c
99call :TestParm       a,,,  b
100goto :TestRem
101
102:TestParm
103echo '%1', '%2', '%3'
104goto :eof
105
106:TestRem
107echo ------------ Testing rem ------------
108rem Hello
109rem  Hello
110rem   Hello || foo
111rem echo lol
112rem echo foo & echo bar
113rem @tab@  Hello
114rem@tab@  Hello
115rem@tab@echo foo & echo bar
116@echo on
117rem Hello
118rem  Hello
119rem   Hello || foo
120rem echo lol
121rem echo foo & echo bar
122rem @tab@  Hello
123rem@tab@  Hello
124rem@tab@echo foo & echo bar
125@echo off
126
127echo ------------ Testing redirection operators ------------
128mkdir foobar & cd foobar
129echo --- stdout redirection
130echo foo>foo
131type foo
132echo foo 1> foo
133type foo
134echo foo@tab@1> foo
135type foo
136echo foo 1>@tab@foo
137type foo
138echo foo@tab@1>@tab@foo
139type foo
140echo foo7 7> foo
141type foo
142echo foo9 9> foo
143type foo
144echo foo1> foo
145type foo
146echo foo11> foo
147type foo
148echo foo12> foo
149type foo
150echo foo13>"foo"
151type foo
152echo foo14>."\foo"
153type foo
154echo foo15>."\f"oo
155type foo
156del foo
157echo1>foo
158type foo
159echo --- stdout appending
160echo foo>foo
161echo foo >>foo
162type foo
163del foo
164echo foob >> foo
165type foo
166echo fooc 1>>foo
167type foo
168echo food1>>foo
169type foo
170echo food2>>"foo"
171type foo
172del foo
173echo food21>>foo
174type foo
175del foo
176echo foo> foo
177echo foo7 7>> foo || (echo not supported & del foo)
178if exist foo (type foo) else echo not supported
179echo --- redirections within IF statements
180if 1==1 echo foo1>bar
181type bar & del bar
182echo -----
183if 1==1 (echo foo2>bar) else echo baz2>bar
184type bar & del bar
185if 1==1 (echo foo3) else echo baz3>bar
186type bar || echo file does not exist, ok
187if 1==1 (echo foo4>bar) else echo baz4>bar
188type bar & del bar
189if 1==0 (echo foo5>bar) else echo baz5>bar
190type bar & del bar
191if 1==0 (echo foo6) else echo baz6 1>bar
192type bar & del bar
193if 1==0 (echo foo7 1>bar) else echo baz7>bar
194type bar & del bar
195if 1==0 (echo foo8 1>bar) else echo baz8>bak
196type bak
197if 1==1 (echo foo>bar & echo baz)
198type bar
199if 1==1 (
200   echo foo>bar
201   echo baz
202)
203type bar
204(if 1==1 (echo A) else echo B) > C
205type C
206(if 1==0 (echo A) else echo B) > C
207type C
208(if 1==0 (echo A > B) else echo C)
209cd .. & rd /s/q foobar
210
211echo ------------ Testing circumflex escape character ------------
212rem Using something like "echo foo^" asks for an additional char after a "More?" prompt on the following line; it's not possible to currently test that non-interactively
213echo ^hell^o, world
214echo hell^o, world
215echo hell^^o, world
216echo hell^^^o, world
217echo hello^
218world
219echo hello^
220
221world
222echo hello^
223
224
225echo finished
226mkdir foobar
227echo baz> foobar\baz
228type foobar\baz
229type foobar^\baz
230rd /s/q foobar
231echo foo ^| echo bar
232echo foo ^& echo bar
233call :setError 0
234echo bak ^&& echo baz 2> nul
235echo %ErrorLevel%
236echo foo ^> foo
237echo ^<> foo
238type foo
239del foo
240set WINE_FOO=oof
241echo ff^%WINE_FOO%
242set WINE_FOO=bar ^| baz
243set WINE_FOO
244rem FIXME: echoing %WINE_FOO% gives an error (baz not recognized) but prematurely
245rem exits the script on windows; redirecting stdout and/or stderr doesn't help
246echo %ErrorLevel%
247call :setError 0
248set WINE_FOO=bar ^^^| baz
249set WINE_FOO
250echo %WINE_FOO%
251echo %ErrorLevel%
252set WINE_FOO=
253
254echo ------------ Testing chains ------------
255rem The chain operators have the following bottom-up precedence:
256rem 'else' precedes nothing and matches the closest unmatched 'if' in the same bracket depth
257rem '&' precedes 'else'
258rem '||' precedes '&' and 'else'
259rem '&&' precedes '||', '&' and 'else'
260rem '|' precedes '&&', '||', '&' and 'else'
261rem
262rem Example: 'if 1==1 if 2==2 if 3==3 a | b && c || d & e else f else g' is interpreted as
263rem          'if 1==1 (if 2==2 (if 3==3 ((((a | b) && c) || d) & e) else f) else g)'
264goto :cfailend
265:cfail
266echo %1
267call :setError 1
268goto :eof
269:cfailend
270echo --- chain success
271echo a1&echo a2
272echo b1&&echo b2
273echo c1||echo c2
274echo ---
275echo d1&echo d2&echo d3
276echo e1&echo e2&&echo e3
277echo f1&echo f2||echo f3
278echo ---
279echo g1&&echo g2&echo g3
280echo h1&&echo h2&&echo h3
281echo i1&&echo i2||echo i3
282echo ---
283echo j1||echo j2&echo j3
284echo ---
285echo k1||echo k2&&echo k3
286echo ---
287echo l1||echo l2||echo l3
288echo ---
289echo --- chain failure
290call :cfail a1&call :cfail a2
291call :cfail b1&&call :cfail b2
292echo ---
293call :cfail c1||call :cfail c2
294call :cfail d1&call :cfail d2&call :cfail d3
295call :cfail e1&call :cfail e2&&call :cfail e3
296echo ---
297call :cfail f1&call :cfail f2||call :cfail f3
298call :cfail g1&&call :cfail g2&call :cfail g3
299echo ---
300call :cfail h1&&call :cfail h2&&call :cfail h3
301echo ---
302call :cfail i1&&call :cfail i2||call :cfail i3
303echo ---
304call :cfail j1||call :cfail j2&call :cfail j3
305call :cfail k1||call :cfail k2&&call :cfail k3
306echo ---
307call :cfail l1||call :cfail l2||call :cfail l3
308echo --- chain brackets
309rem Brackets are like regular commands, they support redirections
310rem and have the same precedence as regular commands.
311echo a1&(echo a2&echo a3)
312echo b1&(echo b2&&echo b3)
313echo c1&(echo c2||echo c3)
314echo ---
315echo d1&&(echo d2&echo d3)
316echo e1&&(echo e2&&echo e3)
317echo f1&&(echo f2||echo f3)
318echo ---
319echo g1||(echo g2&echo g3)
320echo ---
321echo h1||(echo h2&&echo h3)
322echo ---
323echo i1||(echo i2||echo i3)
324echo ---
325call :cfail j1&(call :cfail j2&call :cfail j3)
326call :cfail k1&(call :cfail k2&&call :cfail k3)
327echo ---
328call :cfail l1&(call :cfail l2||call :cfail l3)
329call :cfail m1&&(call :cfail m2&call :cfail m3)
330echo ---
331call :cfail n1&&(call :cfail n2&&call :cfail n3)
332echo ---
333call :cfail o1&&(call :cfail o2||call :cfail o3)
334echo ---
335call :cfail p1||(call :cfail p2&call :cfail p3)
336call :cfail q1||(call :cfail q2&&call :cfail q3)
337echo ---
338call :cfail r1||(call :cfail r2||call :cfail r3)
339echo --- chain pipe
340rem Piped commands run at the same time, so the print order varies.
341rem Additionally, they don't run in the batch script context, as shown by
342rem 'call :existing_label|echo read the error message'.
343(echo a 1>&2|echo a 1>&2) 2>&1
344echo ---
345echo b1|echo b2
346echo c1&&echo c2|echo c3
347echo d1||echo d2|echo d3
348echo ---
349echo e1&echo e2|echo e3
350echo f1|echo f2&&echo f3
351echo g1|echo g2||echo g3
352echo ---
353echo h1|echo h2&echo h3
354echo i1|echo i2|echo i3
355echo --- chain pipe input
356rem The output data of the left side of a pipe can disappear, probably
357rem because it finished too fast and closed the pipe before it could be read,
358rem which means we can get broken results for the tests of this section.
359echo @echo off> tmp.cmd
360echo set IN=X>> tmp.cmd
361echo set /p IN=%%1:>> tmp.cmd
362echo setlocal EnableDelayedExpansion>> tmp.cmd
363echo echo [!IN!,%%1]>> tmp.cmd
364echo endlocal>> tmp.cmd
365echo set IN=>> tmp.cmd
366echo a1|cmd /ctmp.cmd a2
367echo b1|cmd /ctmp.cmd b2|cmd /ctmp.cmd b3
368echo c1|cmd /ctmp.cmd c2|cmd /ctmp.cmd c3|cmd /ctmp.cmd c4
369echo d1|call tmp.cmd d2
370echo e1|call tmp.cmd e2|call tmp.cmd e3
371echo f1|call tmp.cmd f2|call tmp.cmd f3|call tmp.cmd f4
372rem FIXME these 3 tests cause "unexpected end of output"
373rem test  : echo g1|tmp.cmd g2
374rem result: g2:[g1,g2]
375rem test  : echo h1|tmp.cmd h2|tmp.cmd h3
376rem result: h3:[h2:[h1,h2],h3]@or_broken@h3:[h2:,h3]
377rem test  : echo i1|tmp.cmd i2|tmp.cmd i3|tmp.cmd i4
378rem result: i4:[i3:[i2:[i1,i2],i3],i4]@or_broken@i4:[i3:[i2:,i3],i4]@or_broken@i4:[i3:,i4]
379del tmp.cmd
380echo --- chain else
381rem Command arguments are gready and eat up the 'else' unless terminated by
382rem brackets, which means the 'else' can only be recognized when the
383rem 'if true' command chain ends with brackets.
384if 1==1 if 2==2 if 3==3 (echo a1) else (echo a2) else echo a3
385if 1==1 if 2==2 if 3==0 (echo b1) else (echo b2) else echo b3
386echo ---
387if 1==1 if 2==0 if 3==3 (echo c1) else (echo c2) else echo c3
388echo ---
389if 1==1 if 2==0 if 3==0 (echo d1) else (echo d2) else echo d3
390echo ---
391if 1==0 if 2==2 if 3==3 (echo e1) else (echo e2) else echo e3
392echo ---
393if 1==0 if 2==2 if 3==0 (echo f1) else (echo f2) else echo f3
394echo ---
395if 1==0 if 2==0 if 3==3 (echo g1) else (echo g2) else echo g3
396echo ---
397if 1==0 if 2==0 if 3==0 (echo h1) else (echo h2) else echo h3
398echo ---
399echo --- chain else (if true)
400if 1==1 echo a1 else echo a2
401if 1==1 echo b1|echo b2 else echo b3
402if 1==1 echo c1&&echo c2 else echo c3
403if 1==1 echo d1||echo d2 else echo d3
404echo ---
405if 1==1 echo e1&echo e2 else echo e3
406if 1==1 echo f1 else echo f2|echo f3
407if 1==1 echo g1 else echo g2&&echo g3
408if 1==1 echo h1 else echo h2||echo h3
409echo ---
410if 1==1 echo i1 else echo i2&echo i3
411if 1==1 echo j1|(echo j2) else echo j3
412echo ---
413if 1==1 echo k1&&(echo k2) else echo k3
414if 1==1 echo l1||(echo l2) else echo l3
415echo ---
416if 1==1 echo m1&(echo m2) else echo m3
417if 1==1 (echo n1) else echo n2|echo n3
418if 1==1 (echo o1) else echo o2&&echo o3
419if 1==1 (echo p1) else echo p2||echo p3
420if 1==1 (echo q1) else echo q2&echo q3
421echo --- chain else (if false)
422if 1==0 echo a1 else echo a2
423if 1==0 echo b1|echo b2 else echo b3
424if 1==0 echo c1&&echo c2 else echo c3
425if 1==0 echo d1||echo d2 else echo d3
426if 1==0 echo e1&echo e2 else echo e3
427if 1==0 echo f1 else echo f2|echo f3
428if 1==0 echo g1 else echo g2&&echo g3
429if 1==0 echo h1 else echo h2||echo h3
430if 1==0 echo i1 else echo i2&echo i3
431if 1==0 echo j1|(echo j2) else echo j3
432echo ---
433if 1==0 echo k1&&(echo k2) else echo k3
434if 1==0 echo l1||(echo l2) else echo l3
435if 1==0 echo m1&(echo m2) else echo m3
436if 1==0 (echo n1) else echo n2|echo n3
437if 1==0 (echo o1) else echo o2&&echo o3
438if 1==0 (echo p1) else echo p2||echo p3
439echo ---
440if 1==0 (echo q1) else echo q2&echo q3
441echo ------------ Testing 'set' ------------
442call :setError 0
443rem Remove any WINE_FOO* WINE_BA* environment variables from shell before proceeding
444for /f "delims==" %%i in ('set WINE_ba') do set %%i=
445for /f "delims==" %%i in ('set WINE_foo') do set %%i=
446set WINE_FOOBAR 2> nul > nul
447echo %ErrorLevel%
448set WINE_FOOBAR =  baz
449echo %ErrorLevel%
450echo %WINE_FOOBAR%WINE_FOOBAR not defined
451echo %WINE_FOOBAR %
452set WINE_FOOBAR 2> nul
453set WINE_FOOBAR =  baz2
454echo %ErrorLevel%
455echo %WINE_fOObAr %
456set WINE_FOOBAR= bar
457echo %ErrorLevel%
458echo %WINE_FOOBAR%
459set WINE_FOO
460set WINE_FOOBAR=
461set WINE_FOOB
462echo %WINE_FOOBAR%WINE_FOOBAR not defined
463set WINE_FOOBAR =
464set WINE_FOOBA 2> nul > nul
465echo %ErrorLevel%
466set WINE_FOO=bar
467echo %WINE_FOO%
468set WINE_FOO=foo
469set WINE_BAR=bar
470echo %WINE_FOO%%WINE_BAR%
471set WINE_BAR=
472set WINE_FOO=
473set WINE_FOO=%WINE_FOO%
474echo %WINE_FOO%WINE_FOO not defined
475set WINE_BAZ%=bazbaz
476set WINE_BA
477echo %WINE_BAZ%%
478set WINE_BAZ%=
479echo set "WINE_FOO=bar" should not include the quotes in the variable value
480set "WINE_FOO=bar"
481echo %WINE_FOO%
482set@tab@WINE_FOO=foo
483echo %WINE_FOO%
484set@tab@WINE_FOO=
485echo '%WINE_FOO%'
486set WINE_FOO=foo@space@
487echo '%WINE_FOO%'
488set WINE_FOO=foo@tab@
489echo '%WINE_FOO%'
490rem Space symbol must appear in `var`
491set WINE_FOO=value@space@
492echo '%WINE_FOO%'
493rem Space symbol must NOT appear in `var`
494set "WINE_FOO=value"@space@
495echo '%WINE_FOO%'
496rem Mixed examples:
497set WINE_FOO=jim fred
498echo '%WINE_FOO%'
499set WINE_FOO="jim" fred
500echo '%WINE_FOO%'
501set "WINE_FOO=jim fred"
502echo '%WINE_FOO%'
503set "WINE_FOO=jim" fred
504echo '%WINE_FOO%'
505rem Only the final quote ends the string
506set "WINE_FOO=apple"banana"grape"orange
507echo '%WINE_FOO%'
508set WINE_FOO=
509
510echo ------------ Testing variable expansion ------------
511call :setError 0
512echo ~p0 should be path containing batch file
513echo %~p0
514mkdir dummydir
515cd dummydir
516echo %~p0
517cd ..
518rmdir dummydir
519echo ~dp0 should be directory containing batch file
520echo %~dp0
521mkdir dummydir
522cd dummydir
523echo %~dp0
524cd ..
525rmdir dummydir
526echo CD value %CD%
527echo %%
528echo P%
529echo %P
530echo %WINE_UNKNOWN%S
531echo P%WINE_UNKNOWN%
532echo P%WINE_UNKNOWN%S
533echo %ERRORLEVEL
534echo %ERRORLEVEL%
535echo %ERRORLEVEL%%ERRORLEVEL%
536echo %ERRORLEVEL%ERRORLEVEL%
537echo %ERRORLEVEL%%
538echo %ERRORLEVEL%%%
539echo P%ERRORLEVEL%
540echo %ERRORLEVEL%S
541echo P%ERRORLEVEL%S
542
543echo ------------ Testing variable substrings ------------
544set WINE_VAR=qwerty
545echo %WINE_VAR:~0,1%
546echo %WINE_VAR:~0,3%
547echo %WINE_VAR:~2,2%
548echo '%WINE_VAR:~-2,3%'
549echo '%WINE_VAR:~-2,1%'
550echo %WINE_VAR:~2,-1%
551echo %WINE_VAR:~2,-3%
552echo '%WINE_VAR:~-2,-4%'
553echo %WINE_VAR:~-3,-2%
554set WINE_VAR=
555
556echo ------------ Testing variable substitution ------------
557echo --- in FOR variables
558for %%i in ("A B" C) do echo %%i
559rem check works when prefix with @
560@for %%i in ("A B" C) do echo %%i
561rem quotes removal
562for %%i in ("A B" C) do echo '%%~i'
563rem fully qualified path
564for %%f in ("C D" E) do echo %%~ff
565rem drive letter
566for %%i in ("F G" H) do echo %%~di
567rem path
568for %%d in ("I J" K) do echo %%~pd
569rem filename
570for %%i in ("L M" N) do echo %%~ni
571rem file extension
572for %%i in ("O. P.OOL" Q.TABC hello) do echo '%%~xi'
573rem path with short path names
574for %%I in ("R S" T ABCDEFGHIJK.LMNOP) do echo '%%~sI'
575rem file attribute
576for %%i in ("U V" W) do echo '%%~ai'
577echo foo> foo
578for %%i in (foo) do echo '%%~ai'
579for %%i in (foo) do echo '%%~zi'
580del foo
581rem file date/time
582rem Not fully testable, until we can grep dir's output to get foo's creation time in an envvar...
583for %%i in ("a b" c) do echo '%%~ti'
584rem file size
585rem Similar issues as above
586for %%i in ("a b" c) do echo '%%~zi'
587rem combined options
588for %%i in ("d e" f) do echo %%~dpi
589for %%i in ("g h" i) do echo %%~sdi
590for %%i in ("g h" i) do echo %%~dsi
591for %%i in ("j k" l.eh) do echo '%%~xsi'
592for %%i in ("") do echo '%%~i,%%~fi,%%~di,%%~pi,%%~ni,%%~xi,%%~si,%%~ai,%%~ti,%%~zi'
593
594echo --- in parameters
595for %%i in ("A B" C) do call :echoFun %%i
596rem quotes removal
597for %%i in ("A B" C) do call :echoFunQ %%i
598rem fully qualified path
599for %%f in ("C D" E) do call :echoFunF %%f
600rem drive letter
601for %%i in ("F G" H) do call :echoFunD %%i
602rem path
603for %%d in ("I J" K) do call :echoFunP %%d
604rem filename
605for %%i in ("L M" N) do call :echoFunN %%i
606rem file extension
607for %%i in ("O. P.OOL" Q.TABC hello) do call :echoFunX %%i
608rem path with short path names
609for %%I in ("R S" T ABCDEFGHIJK.LMNOP) do call :echoFunS %%I
610rem NT4 aborts whole script execution when encountering ~a, ~t and ~z substitutions, preventing full testing
611rem combined options
612for %%i in ("d e" f) do call :echoFunDP %%i
613for %%i in ("g h" i) do call :echoFunSD %%i
614for %%i in ("g h" i) do call :echoFunDS %%i
615for %%i in ("j k" l.eh) do call :echoFunXS %%i
616
617goto :endEchoFuns
618:echoFun
619echo %1
620goto :eof
621
622:echoFunQ
623echo '%~1'
624goto :eof
625
626:echoFunF
627echo %~f1
628goto :eof
629
630:echoFunD
631echo %~d1
632goto :eof
633
634:echoFunP
635echo %~p1
636goto :eof
637
638:echoFunN
639echo %~n1
640goto :eof
641
642:echoFunX
643echo '%~x1'
644goto :eof
645
646:echoFunS
647rem some NT4 workaround
648set WINE_VAR='%~s1'
649echo %WINE_VAR%
650set WINE_VAR=
651goto :eof
652
653:echoFunDP
654echo %~dp1
655goto :eof
656
657:echoFunSD
658echo %~sd1
659goto :eof
660
661:echoFunDS
662echo %~ds1
663goto :eof
664
665:echoFunXS
666echo '%~xs1'
667goto :eof
668:endEchoFuns
669
670echo ------------ Testing variable delayed expansion ------------
671rem NT4 doesn't support this
672echo --- default mode (load-time expansion)
673set WINE_FOO=foo
674echo %WINE_FOO%
675echo !WINE_FOO!
676if %WINE_FOO% == foo (
677    set WINE_FOO=bar
678    if %WINE_FOO% == bar (echo bar) else echo foo
679)
680
681set WINE_FOO=foo
682if %WINE_FOO% == foo (
683    set WINE_FOO=bar
684    if !WINE_FOO! == bar (echo bar) else echo foo
685)
686
687echo --- runtime (delayed) expansion mode
688setlocal EnableDelayedExpansion
689set WINE_FOO=foo
690echo %WINE_FOO%
691echo !WINE_FOO!
692if %WINE_FOO% == foo (
693    set WINE_FOO=bar
694    if %WINE_FOO% == bar (echo bar) else echo foo
695)
696
697set WINE_FOO=foo
698if %WINE_FOO% == foo (
699    set WINE_FOO=bar
700    if !WINE_FOO! == bar (echo bar) else echo foo
701)
702echo %ErrorLevel%
703setlocal DisableDelayedExpansion
704echo %ErrorLevel%
705set WINE_FOO=foo
706echo %WINE_FOO%
707echo !WINE_FOO!
708set WINE_FOO=
709echo --- using /V cmd flag
710echo @echo off> tmp.cmd
711echo set WINE_FOO=foo>> tmp.cmd
712echo echo %%WINE_FOO%%>> tmp.cmd
713echo echo !WINE_FOO!>> tmp.cmd
714echo set WINE_FOO=>> tmp.cmd
715cmd /V:ON /C tmp.cmd
716cmd /V:OfF /C tmp.cmd
717del tmp.cmd
718
719echo ------------ Testing conditional execution ------------
720echo --- unconditional ampersand
721call :setError 123 & echo foo1
722echo bar2 & echo foo2
723mkdir foobar & cd foobar
724echo > foobazbar
725cd .. & rd /s/q foobar
726if exist foobazbar (
727    echo foobar not deleted!
728    cd ..
729    rd /s/q foobar
730) else echo foobar deleted
731echo --- on success conditional and
732call :setError 456 && echo foo3 > foo3
733if exist foo3 (
734    echo foo3 created
735    del foo3
736) else echo foo3 not created
737echo bar4 && echo foo4
738echo --- on failure conditional or
739call :setError 789 || echo foo5
740echo foo6 || echo bar6 > bar6
741if exist bar6 (
742    echo bar6 created
743    del bar6
744)
745
746echo ------------ Testing cd ------------
747mkdir foobar
748cd foobar
749echo blabla > singleFile
750dir /b
751echo Current dir: %CD%
752cd
753cd ..
754cd
755cd foobar@space@
756cd
757cd ..
758cd
759cd @space@foobar
760cd
761cd..
762cd
763cd foobar
764cd..@space@
765cd
766if not exist foobar (cd ..)
767cd foobar
768cd@tab@..@tab@@space@@tab@
769cd
770if not exist foobar (cd ..)
771cd foobar
772mkdir "bar bak"
773cd "bar bak"
774cd
775cd ..
776cd ".\bar bak"
777cd
778cd ..
779cd .\"bar bak"
780cd
781cd ..
782cd bar bak
783cd
784cd "bar bak@space@"@tab@@space@
785cd
786cd ..\..
787cd
788rd /Q/s foobar
789mkdir foobar
790cd /d@tab@foobar
791cd
792cd ..
793rd /q/s foobar
794
795echo ------------ Testing type ------------
796echo bar> foobaz
797@echo on
798type foobaz
799echo ---
800@echo off
801type foobaz@tab@
802echo ---1
803type ."\foobaz"
804echo ---2
805type ".\foobaz"
806echo ---3
807del foobaz
808
809echo ------------ Testing NUL ------------
810md foobar & cd foobar
811rem NUL file (non) creation + case insensitivity
812rem Note: "if exist" does not work with NUL, so to check for file existence we use a kludgy workaround
813echo > bar
814echo foo > NUL
815dir /b /a-d
816echo foo > nul
817dir /b /a-d
818echo foo > NuL
819@tab@dir /b@tab@/a-d
820del bar
821rem NUL not special everywhere
822call :setError 123
823echo NUL> foo
824if not exist foo (echo foo should have been created) else (
825    type foo
826    del foo
827)
828rem Empty file creation
829copy nul foo > nul
830if exist foo (
831    echo foo created
832    del foo
833    type foo
834) else (
835    echo ***
836)
837echo 1234 >a.a
838copy a.a+NUL b.b >nul
839call :CheckFileSize a.a 7 b.b 8
840copy NUL+a.a b.b >nul
841call :CheckFileSize a.a 7 b.b 8
842mkdir subdir
843copy a.a+NUL subdir\ >nul
844call :CheckFileSize a.a 7 subdir\a.a 8
845del subdir\a.a
846cd subdir
847copy ..\a.a NUL >nul
848if exist a.a echo Failed
849cd ..
850rd subdir /s /q
851del a.a b.b
852cd .. & rd foobar /s /q
853
854echo ------------ Testing if/else ------------
855echo --- if/else should work with blocks
856if 0 == 0 (
857  echo if seems to work
858) else (
859  echo if seems to be broken
860)
861if 1 == 0 (
862  echo else seems to be broken
863) else (
864  echo else seems to work
865)
866if /c==/c (
867  echo if seems not to detect /c as parameter
868) else (
869  echo parameter detection seems to be broken
870)
871SET elseIF=0
872if 1 == 1 (
873  SET /a elseIF=%elseIF%+1
874) else if 1 == 1 (
875  SET /a elseIF=%elseIF%+2
876) else (
877  SET /a elseIF=%elseIF%+2
878)
879if %elseIF% == 1 (
880  echo else if seems to work
881) else (
882  echo else if seems to be broken
883)
884SET elseIF=0
885if 1 == 2 (
886  SET /a elseIF=%elseIF%+2
887) else if 1 == 1 (
888  SET /a elseIF=%elseIF%+1
889) else (
890  SET /a elseIF=%elseIF%+2
891)
892if %elseIF% == 1 (
893  echo else if seems to work
894) else (
895  echo else if seems to be broken
896)
897SET elseIF=0
898if 1 == 2 (
899  SET /a elseIF=%elseIF%+2
900) else if 1 == 2 (
901  SET /a elseIF=%elseIF%+2
902) else (
903  SET /a elseIF=%elseIF%+1
904)
905if %elseIF% == 1 (
906  echo else if seems to work
907) else (
908  echo else if seems to be broken
909)
910echo --- case sensitivity with and without /i option
911if bar==BAR echo if does not default to case sensitivity
912if not bar==BAR echo if seems to default to case sensitivity
913if /i foo==FOO echo if /i seems to work
914if /i not foo==FOO echo if /i seems to be broken
915if /I foo==FOO echo if /I seems to work
916if /I not foo==FOO echo if /I seems to be broken
917
918echo --- string comparisons
919if abc == abc  (echo equal) else echo non equal
920if abc =="abc" (echo equal) else echo non equal
921if "abc"== abc (echo equal) else echo non equal
922if "abc"== "abc" (echo equal) else echo non equal
923
924echo --- tabs handling
925if@tab@1==1 echo doom
926if @tab@1==1 echo doom
927if 1==1 (echo doom) else@tab@echo quake
928if@tab@not @tab@1==@tab@0 @tab@echo lol
929if 1==0@tab@(echo doom) else echo quake
930if 1==0 (echo doom)@tab@else echo quake
931if 1==0 (echo doom) else@tab@echo quake
932
933echo --- comparison operators
934rem NT4 misevaluates conditionals in for loops so we have to use subroutines as workarounds
935echo ------ for strings
936rem NT4 stops processing of the whole batch file as soon as it finds a
937rem comparison operator non fully uppercased, such as lss instead of LSS, so we
938rem can't test those here.
939if LSS LSS LSSfoo (echo LSS string can be used as operand for LSS comparison)
940if LSS LSS LSS (echo bar)
941if 1.1 LSS 1.10 (echo floats are handled as strings)
942if "9" LSS "10" (echo numbers in quotes recognized!) else echo numbers in quotes are handled as strings
943if not "-1" LSS "1" (echo negative numbers as well) else echo NT4
944if /i foo LSS FoOc echo if /i seems to work for LSS
945if /I not foo LSS FOOb echo if /I seems to be broken for LSS
946set WINE_STR_PARMS=A B AB BA AA
947for %%i in (%WINE_STR_PARMS%) do (
948    for %%j in (%WINE_STR_PARMS%) do (
949        call :LSStest %%i %%j))
950if b LSS B (echo b LSS B) else echo NT4
951if /I b LSS B echo b LSS B insensitive
952if b LSS A echo b LSS A
953if /I b LSS A echo b LSS A insensitive
954if a LSS B (echo a LSS B) else echo NT4
955if /I a LSS B echo a LSS B insensitive
956if A LSS b echo A LSS b
957if /I A LSS b echo A LSS b insensitive
958for %%i in (%WINE_STR_PARMS%) do (
959    for %%j in (%WINE_STR_PARMS%) do (
960        call :LEQtest %%i %%j))
961if b LEQ B (echo b LEQ B) else echo NT4
962if /I b LEQ B echo b LEQ B insensitive
963if b LEQ A echo b LEQ A
964if /I b LEQ A echo b LEQ A insensitive
965if a LEQ B (echo a LEQ B) else echo NT4
966if /I a LEQ B echo a LEQ B insensitive
967if A LEQ b echo A LEQ b
968if /I A LEQ b echo A LEQ b insensitive
969for %%i in (%WINE_STR_PARMS%) do (
970    for %%j in (%WINE_STR_PARMS%) do (
971        call :EQUtest %%i %%j))
972if /I A EQU a echo A EQU a insensitive
973for %%i in (%WINE_STR_PARMS%) do (
974    for %%j in (%WINE_STR_PARMS%) do (
975        call :NEQtest %%i %%j))
976for %%i in (%WINE_STR_PARMS%) do (
977    for %%j in (%WINE_STR_PARMS%) do (
978        call :GEQtest %%i %%j))
979for %%i in (%WINE_STR_PARMS%) do (
980    for %%j in (%WINE_STR_PARMS%) do (
981        call :GTRtest %%i %%j))
982echo ------ for numbers
983if -1 LSS 1 (echo negative numbers handled)
984if not -1 LSS -10 (echo negative numbers handled)
985if not 9 LSS 010 (echo octal handled)
986if not -010 LSS -8 (echo also in negative form)
987if 4 LSS 0x5 (echo hexa handled)
988if not -1 LSS -0x1A (echo also in negative form)
989if 11 LSS 101 (echo 11 LSS 101)
990set WINE_INT_PARMS=0 1 10 9
991for %%i in (%WINE_INT_PARMS%) do (
992    for %%j in (%WINE_INT_PARMS%) do (
993        call :LSStest %%i %%j))
994for %%i in (%WINE_INT_PARMS%) do (
995    for %%j in (%WINE_INT_PARMS%) do (
996        call :LEQtest %%i %%j))
997for %%i in (%WINE_INT_PARMS%) do (
998    for %%j in (%WINE_INT_PARMS%) do (
999        call :EQUtest %%i %%j))
1000if 011 EQU 9 (echo octal ok)
1001if 0xA1 EQU 161 (echo hexa ok)
1002if 0xA1 EQU "161" (echo hexa should be recognized) else (echo string/hexa compare ok)
1003if "0xA1" EQU 161 (echo hexa should be recognized) else (echo string/hexa compare ok)
1004for %%i in (%WINE_INT_PARMS%) do (
1005    for %%j in (%WINE_INT_PARMS%) do (
1006        call :NEQtest %%i %%j))
1007for %%i in (%WINE_INT_PARMS%) do (
1008    for %%j in (%WINE_INT_PARMS%) do (
1009        call :GEQtest %%i %%j))
1010for %%i in (%WINE_INT_PARMS%) do (
1011    for %%j in (%WINE_INT_PARMS%) do (
1012        call :GTRtest %%i %%j))
1013echo ------ for numbers and stringified numbers
1014if not "1" EQU 1 (echo strings and integers not equal) else echo foo
1015if not 1 EQU "1" (echo strings and integers not equal) else echo foo
1016if '1' EQU 1 echo '1' EQU 1
1017if 1 EQU '1' echo 1 EQU '1'
1018if not "1" GEQ 1 (echo foo) else echo bar
1019if "10" GEQ "1" echo "10" GEQ "1"
1020if '1' GEQ 1 (echo '1' GEQ 1) else echo NT4
1021if 1 GEQ "1" echo 1 GEQ "1"
1022if "1" GEQ "1" echo "1" GEQ "1"
1023if '1' GEQ "1" echo '1' GEQ "1"
1024if "10" GEQ "1" echo "10" GEQ "1"
1025if not 1 GEQ '1' (echo non NT4) else echo 1 GEQ '1'
1026for %%i in ("1" '1') do call :GEQtest %%i '1'
1027if "10" GEQ '1' (echo "10" GEQ '1') else echo foo
1028if 1 GEQ "10" (echo 1 GEQ "10") else echo foo
1029if "1" GEQ "10" (echo 1 GEQ "10") else echo foo
1030if '1' GEQ "10" (echo '1' GEQ "10") else echo foo
1031if "10" GEQ "10" (echo "10" GEQ "10")
1032echo --- unconditional ampersand after if one line
1033if "0"=="0" echo 1 & echo 2 & echo 3 else echo 4
1034echo ---
1035echo x & if "0"=="1" echo 1 & echo 2
1036echo ---
1037echo x & if "0"=="1" echo 1 & echo 2 & echo 3
1038echo ---
1039echo x & if "0"=="1" (echo 1 & echo 2 & echo 3)
1040echo ---
1041echo x & if "0"=="1" echo 1 & echo 2 & echo 3 else echo 4
1042echo ---
1043goto :endIfCompOpsSubroutines
1044
1045rem IF subroutines helpers
1046:LSStest
1047if %1 LSS %2 echo %1 LSS %2
1048goto :eof
1049:LEQtest
1050if %1 LEQ %2 echo %1 LEQ %2
1051goto :eof
1052:EQUtest
1053if %1 EQU %2 echo %1 EQU %2
1054goto :eof
1055:NEQtest
1056if %1 NEQ %2 echo %1 NEQ %2
1057goto :eof
1058:GEQtest
1059if %1 GEQ %2 echo %1 GEQ %2
1060goto :eof
1061:GTRtest
1062if %1 GTR %2 echo %1 GTR %2
1063goto :eof
1064
1065:endIfCompOpsSubroutines
1066set WINE_STR_PARMS=
1067set WINE_INT_PARMS=
1068
1069echo ------------ Testing for ------------
1070echo --- plain FOR
1071for %%i in (A B C) do echo %%i
1072for %%i in (A B C) do echo %%I
1073for %%i in (A B C) do echo %%j
1074for %%i in (A B C) do call :forTestFun1 %%i
1075for %%i in (1,4,1) do echo %%i
1076for %%i in (A, B,C) do echo %%i
1077for %%i in  (X) do echo %%i
1078for@tab@%%i in  (X2) do echo %%i
1079for %%i in@tab@(X3) do echo %%i
1080for %%i in (@tab@ foo@tab@) do echo %%i
1081for@tab@ %%i in@tab@(@tab@M) do echo %%i
1082for %%i@tab@in (X)@tab@do@tab@echo %%i
1083for@tab@ %%j in@tab@(@tab@M, N, O@tab@) do echo %%j
1084for %%i in (`echo A B`) do echo %%i
1085for %%i in ('echo A B') do echo %%i
1086for %%i in ("echo A B") do echo %%i
1087for %%i in ("A B" C) do echo %%i
1088goto :endForTestFun1
1089:forTestFun1
1090echo %1
1091goto :eof
1092:endForTestFun1
1093echo --- imbricated FORs
1094for %%i in (X) do (
1095    for %%j in (Y) do (
1096        echo %%i %%j))
1097for %%i in (X) do (
1098    for %%I in (Y) do (
1099        echo %%i %%I))
1100for %%i in (A B) do (
1101    for %%j in (C D) do (
1102        echo %%i %%j))
1103for %%i in (A B) do (
1104    for %%j in (C D) do (
1105        call :forTestFun2 %%i %%j ))
1106goto :endForTestFun2
1107:forTestFun2
1108echo %1 %2
1109goto :eof
1110:endForTestFun2
1111mkdir foobar & cd foobar
1112mkdir foo
1113mkdir bar
1114mkdir baz
1115echo > bazbaz
1116echo --- basic wildcards
1117for %%i in (ba*) do echo %%i
1118echo --- for /d
1119for /d %%i in (baz foo bar) do echo %%i 2>&1
1120rem Confirm we don't match files:
1121for /d %%i in (bazb*) do echo %%i 2>&1
1122for /d %%i in (bazb2*) do echo %%i 2>&1
1123rem Show we pass through non wildcards
1124for /d %%i in (PASSED) do echo %%i
1125for /d %%i in (xxx) do (
1126  echo %%i - Should be xxx
1127  echo Expected second line
1128)
1129rem Show we issue no messages on failures
1130for /d %%i in (FAILED?) do echo %%i 2>&1
1131for /d %%i in (FAILED?) do (
1132  echo %%i - Unexpected!
1133  echo FAILED Unexpected second line
1134)
1135for /d %%i in (FAILED*) do echo %%i 2>&1
1136for /d %%i in (FAILED*) do (
1137  echo %%i - Unexpected!
1138  echo FAILED Unexpected second line
1139)
1140rem FIXME can't test wildcard expansion here since it's listed in directory
1141rem order, and not in alphabetic order.
1142rem Proper testing would need a currently missing "sort" program implementation.
1143rem for /d %%i in (ba*) do echo %%i>> tmp
1144rem sort < tmp
1145rem del tmp
1146rem for /d %%i in (?a*) do echo %%i>> tmp
1147rem sort < tmp
1148rem del tmp
1149rem for /d %%i in (*) do echo %%i>> tmp
1150rem sort < tmp
1151rem del tmp
1152echo > baz\bazbaz
1153goto :TestForR
1154
1155:SetExpected
1156del temp.bat 2>nul
1157call :WriteLine set WINE_found=N
1158for /l %%i in (1,1,%WINE_expectedresults%) do (
1159  call :WriteLine if "%%%%WINE_expectedresults.%%i%%%%"=="%%%%~1" set WINE_found=Y
1160  call :WriteLine if "%%%%WINE_found%%%%"=="Y" set WINE_expectedresults.%%i=
1161  call :WriteLine if "%%%%WINE_found%%%%"=="Y" goto :eof
1162)
1163call :WriteLine echo Got unexpected result: "%%%%~1"
1164goto :eof
1165
1166:WriteLine
1167echo %*>> temp.bat
1168goto :EOF
1169
1170:ValidateExpected
1171del temp.bat 2>nul
1172for /l %%i in (1,1,%WINE_expectedresults%) do (
1173  call :WriteLine if not "%%%%WINE_expectedresults.%%i%%%%"=="" echo Found missing result: "%%%%WINE_expectedresults.%%i%%%%"
1174)
1175call temp.bat
1176del temp.bat 2>nul
1177goto :eof
1178
1179:TestForR
1180rem %CD% does not work on NT4 so use the following workaround
1181for /d %%i in (.) do set WINE_CURDIR=%%~dpnxi
1182
1183echo --- for /R
1184echo Plain directory enumeration
1185set WINE_expectedresults=4
1186set WINE_expectedresults.1=%WINE_CURDIR%\.
1187set WINE_expectedresults.2=%WINE_CURDIR%\bar\.
1188set WINE_expectedresults.3=%WINE_CURDIR%\baz\.
1189set WINE_expectedresults.4=%WINE_CURDIR%\foo\.
1190call :SetExpected
1191for /R %%i in (.) do call temp.bat "%%i"
1192call :ValidateExpected
1193
1194echo Plain directory enumeration from provided root
1195set WINE_expectedresults=4
1196set WINE_expectedresults.1=%WINE_CURDIR%\.
1197set WINE_expectedresults.2=%WINE_CURDIR%\bar\.
1198set WINE_expectedresults.3=%WINE_CURDIR%\baz\.
1199set WINE_expectedresults.4=%WINE_CURDIR%\foo\.
1200if "%CD%"=="" goto :SkipBrokenNT4
1201call :SetExpected
1202for /R "%WINE_CURDIR%" %%i in (.) do call temp.bat "%%i"
1203call :ValidateExpected
1204:SkipBrokenNT4
1205
1206echo File enumeration
1207set WINE_expectedresults=2
1208set WINE_expectedresults.1=%WINE_CURDIR%\baz\bazbaz
1209set WINE_expectedresults.2=%WINE_CURDIR%\bazbaz
1210call :SetExpected
1211for /R %%i in (baz*) do call temp.bat "%%i"
1212call :ValidateExpected
1213
1214echo File enumeration from provided root
1215set WINE_expectedresults=2
1216set WINE_expectedresults.1=%WINE_CURDIR%\baz\bazbaz
1217set WINE_expectedresults.2=%WINE_CURDIR%\bazbaz
1218call :SetExpected
1219for /R %%i in (baz*) do call temp.bat "%%i"
1220call :ValidateExpected
1221
1222echo Mixed enumeration
1223set WINE_expectedresults=6
1224set WINE_expectedresults.1=%WINE_CURDIR%\.
1225set WINE_expectedresults.2=%WINE_CURDIR%\bar\.
1226set WINE_expectedresults.3=%WINE_CURDIR%\baz\.
1227set WINE_expectedresults.4=%WINE_CURDIR%\baz\bazbaz
1228set WINE_expectedresults.5=%WINE_CURDIR%\bazbaz
1229set WINE_expectedresults.6=%WINE_CURDIR%\foo\.
1230call :SetExpected
1231for /R %%i in (. baz*) do call temp.bat "%%i"
1232call :ValidateExpected
1233
1234echo Mixed enumeration from provided root
1235set WINE_expectedresults=6
1236set WINE_expectedresults.1=%WINE_CURDIR%\.
1237set WINE_expectedresults.2=%WINE_CURDIR%\bar\.
1238set WINE_expectedresults.3=%WINE_CURDIR%\baz\.
1239set WINE_expectedresults.4=%WINE_CURDIR%\baz\bazbaz
1240set WINE_expectedresults.5=%WINE_CURDIR%\bazbaz
1241set WINE_expectedresults.6=%WINE_CURDIR%\foo\.
1242call :SetExpected
1243for /R %%i in (. baz*) do call temp.bat "%%i"
1244call :ValidateExpected
1245
1246echo With duplicates enumeration
1247set WINE_expectedresults=12
1248set WINE_expectedresults.1=%WINE_CURDIR%\bar\bazbaz
1249set WINE_expectedresults.2=%WINE_CURDIR%\bar\fred
1250set WINE_expectedresults.3=%WINE_CURDIR%\baz\bazbaz
1251set WINE_expectedresults.4=%WINE_CURDIR%\baz\bazbaz
1252set WINE_expectedresults.5=%WINE_CURDIR%\baz\bazbaz
1253set WINE_expectedresults.6=%WINE_CURDIR%\baz\fred
1254set WINE_expectedresults.7=%WINE_CURDIR%\bazbaz
1255set WINE_expectedresults.8=%WINE_CURDIR%\bazbaz
1256set WINE_expectedresults.9=%WINE_CURDIR%\bazbaz
1257set WINE_expectedresults.10=%WINE_CURDIR%\foo\bazbaz
1258set WINE_expectedresults.11=%WINE_CURDIR%\foo\fred
1259set WINE_expectedresults.12=%WINE_CURDIR%\fred
1260call :SetExpected
1261for /R %%i in (baz* bazbaz fred ba*) do call temp.bat "%%i"
1262call :ValidateExpected
1263
1264echo Strip missing wildcards, keep unwildcarded names
1265set WINE_expectedresults=6
1266set WINE_expectedresults.1=%WINE_CURDIR%\bar\jim
1267set WINE_expectedresults.2=%WINE_CURDIR%\baz\bazbaz
1268set WINE_expectedresults.3=%WINE_CURDIR%\baz\jim
1269set WINE_expectedresults.4=%WINE_CURDIR%\bazbaz
1270set WINE_expectedresults.5=%WINE_CURDIR%\foo\jim
1271set WINE_expectedresults.6=%WINE_CURDIR%\jim
1272call :SetExpected
1273for /R %%i in (baz* fred* jim) do call temp.bat "%%i"
1274call :ValidateExpected
1275
1276echo for /R passed
1277echo --- Complex wildcards unix and windows slash
1278cd ..
1279echo Windows slashes, valid path
1280for %%f in (foobar\baz\bazbaz) do echo ASIS: %%f
1281for %%f in (foobar\baz\*) do echo WC  : %%f
1282echo Windows slashes, invalid path
1283for %%f in (foobar\jim\bazbaz) do echo ASIS: %%f
1284for %%f in (foobar\jim\*) do echo WC  : %%f
1285echo Unix slashes, valid path
1286for %%f in (foobar/baz/bazbaz) do echo ASIS: %%f
1287for %%f in (foobar/baz/*) do echo WC  : %%f
1288echo Unix slashes, invalid path
1289for %%f in (foobar/jim/bazbaz) do echo ASIS: %%f
1290for %%f in (foobar/jim/*) do echo WC  : %%f
1291echo Done
1292rd /s/Q foobar
1293echo --- for /L
1294rem Some cases loop forever writing 0s, like e.g. (1,0,1), (1,a,3) or (a,b,c); those can't be tested here
1295for /L %%i in (1,2,0) do echo %%i
1296for@tab@/L %%i in (1,2,0) do echo %%i
1297for /L %%i in (1,2,6) do echo %%i
1298for /l %%i in (1 ,2,6) do echo %%i
1299for /L %%i in (a,2,3) do echo %%i
1300for /L %%i in (1,2,-1) do echo %%i
1301for /L %%i in (-4,-1,-1) do echo %%i
1302for /L %%i in (1,-2,-2) do echo %%i
1303for /L %%i in (1,2,a) do echo %%i
1304echo ErrorLevel %ErrorLevel%
1305for /L %%i in (1,a,b) do echo %%i
1306echo ErrorLevel %ErrorLevel%
1307rem Test boundaries
1308for /l %%i in (1,1,4) do echo %%i
1309for /l %%i in (1,2,4) do echo %%i
1310for /l %%i in (4,-1,1) do echo %%i
1311for /l %%i in (4,-2,1) do echo %%i
1312for /l %%i in (1,-1,4) do echo %%i
1313for /l %%i in (4,1,1) do echo %%i
1314for /L %%i in (a,2,b) do echo %%i
1315for /L %%i in (1,1,1) do echo %%i
1316for /L %%i in (1,-2,-1) do echo %%i
1317for /L %%i in (-1,-1,-1) do echo %%i
1318for /L %%i in (1,2, 3) do echo %%i
1319rem Test zero iteration skips the body of the for
1320for /L %%i in (2,2,1) do (
1321  echo %%i
1322  echo FAILED
1323)
1324echo --- set /a
1325goto :testseta
1326
1327Rem Ideally for /f can be used rather than building a command to execute
1328rem but that does not work on NT4
1329:checkenvvars
1330if "%1"=="" goto :eof
1331call :executecmd set wine_result=%%%1%%
1332if "%wine_result%"=="%2" (
1333  echo %1 correctly %2
1334) else echo ERROR: %1 incorrectly %wine_result% [%2]
1335set %1=
1336shift
1337shift
1338rem shift
1339goto :checkenvvars
1340:executecmd
1341%*
1342goto :eof
1343
1344:testseta
1345rem No output when using "set expr" syntax, unless in interactive mode
1346rem Need to use "set envvar=expr" to use in a batch script
1347echo ------ individual operations
1348set WINE_foo=0
1349set /a WINE_foo=1 +2 & call :checkenvvars WINE_foo 3
1350set /a WINE_foo=1 +-2 & call :checkenvvars WINE_foo -1
1351set /a WINE_foo=1 --2 & call :checkenvvars WINE_foo 3
1352set /a WINE_foo=2* 3 & call :checkenvvars WINE_foo 6
1353set /a WINE_foo=-2* -5 & call :checkenvvars WINE_foo 10
1354set /a WINE_foo=12/3 & call :checkenvvars WINE_foo 4
1355set /a WINE_foo=13/3 & call :checkenvvars WINE_foo 4
1356set /a WINE_foo=-13/3 & call :checkenvvars WINE_foo -4
1357rem FIXME Divide by zero should return an error, but error messages cannot be tested with current infrastructure
1358set /a WINE_foo=5 %% 5 & call :checkenvvars WINE_foo 0
1359set /a WINE_foo=5 %% 3 & call :checkenvvars WINE_foo 2
1360set /a WINE_foo=5 %% -3 & call :checkenvvars WINE_foo 2
1361set /a WINE_foo=-5 %% -3 & call :checkenvvars WINE_foo -2
1362set /a WINE_foo=1 ^<^< 0 & call :checkenvvars WINE_foo 1
1363set /a WINE_foo=1 ^<^< 2 & call :checkenvvars WINE_foo 4
1364set /a WINE_foo=1 ^<^< -2 & call :checkenvvars WINE_foo 0
1365set /a WINE_foo=-1 ^<^< -2 & call :checkenvvars WINE_foo 0
1366set /a WINE_foo=-1 ^<^< 2 & call :checkenvvars WINE_foo -4
1367set /a WINE_foo=9 ^>^> 0 & call :checkenvvars WINE_foo 9
1368set /a WINE_foo=9 ^>^> 2 & call :checkenvvars WINE_foo 2
1369set /a WINE_foo=9 ^>^> -2 & call :checkenvvars WINE_foo 0
1370set /a WINE_foo=-9 ^>^> -2 & call :checkenvvars WINE_foo -1
1371set /a WINE_foo=-9 ^>^> 2 & call :checkenvvars WINE_foo -3
1372set /a WINE_foo=5 ^& 0 & call :checkenvvars WINE_foo 0
1373set /a WINE_foo=5 ^& 1 & call :checkenvvars WINE_foo 1
1374set /a WINE_foo=5 ^& 3 & call :checkenvvars WINE_foo 1
1375set /a WINE_foo=5 ^& 4 & call :checkenvvars WINE_foo 4
1376set /a WINE_foo=5 ^& 1 & call :checkenvvars WINE_foo 1
1377set /a WINE_foo=5 ^| 0 & call :checkenvvars WINE_foo 5
1378set /a WINE_foo=5 ^| 1 & call :checkenvvars WINE_foo 5
1379set /a WINE_foo=5 ^| 3 & call :checkenvvars WINE_foo 7
1380set /a WINE_foo=5 ^| 4 & call :checkenvvars WINE_foo 5
1381set /a WINE_foo=5 ^| 1 & call :checkenvvars WINE_foo 5
1382set /a WINE_foo=5 ^^ 0 & call :checkenvvars WINE_foo 5
1383set /a WINE_foo=5 ^^ 1 & call :checkenvvars WINE_foo 4
1384set /a WINE_foo=5 ^^ 3 & call :checkenvvars WINE_foo 6
1385set /a WINE_foo=5 ^^ 4 & call :checkenvvars WINE_foo 1
1386set /a WINE_foo=5 ^^ 1 & call :checkenvvars WINE_foo 4
1387echo ------ precedence and grouping
1388set /a WINE_foo=4 + 2*3 & call :checkenvvars WINE_foo 10
1389set /a WINE_foo=(4+2)*3 & call :checkenvvars WINE_foo 18
1390set /a WINE_foo=4 * 3/5 & call :checkenvvars WINE_foo 2
1391set /a WINE_foo=(4 * 3)/5 & call :checkenvvars WINE_foo 2
1392set /a WINE_foo=4 * 5 %% 4 & call :checkenvvars WINE_foo 0
1393set /a WINE_foo=4 * (5 %% 4) & call :checkenvvars WINE_foo 4
1394set /a WINE_foo=3 %% (5 + 8 %% 3 ^^ 2) & call :checkenvvars WINE_foo 3
1395set /a WINE_foo=3 %% (5 + 8 %% 3 ^^ -2) & call :checkenvvars WINE_foo 3
1396echo ------ octal and hexadecimal
1397set /a WINE_foo=0xf + 3 & call :checkenvvars WINE_foo 18
1398set /a WINE_foo=0xF + 3 & call :checkenvvars WINE_foo 18
1399set /a WINE_foo=015 + 2 & call :checkenvvars WINE_foo 15
1400set /a WINE_foo=3, 8+3,0 & call :checkenvvars WINE_foo 3
1401echo ------ variables
1402set /a WINE_foo=WINE_bar=3, WINE_bar+1 & call :checkenvvars WINE_foo 3 WINE_bar 3
1403set /a WINE_foo=WINE_bar=3, WINE_bar+=1 & call :checkenvvars WINE_foo 3 WINE_bar 4
1404set /a WINE_foo=WINE_bar=3, WINE_baz=1, WINE_baz+=WINE_bar, WINE_baz & call :checkenvvars WINE_foo 3 WINE_bar 3 WINE_baz 4
1405set WINE_bar=3
1406set /a WINE_foo=WINE_bar*= WINE_bar & call :checkenvvars WINE_foo 9 WINE_bar 9
1407set /a WINE_foo=WINE_whateverNonExistingVar & call :checkenvvars WINE_foo 0
1408set WINE_bar=4
1409set /a WINE_foo=WINE_whateverNonExistingVar + WINE_bar & call :checkenvvars WINE_foo 4 WINE_bar 4
1410set WINE_bar=4
1411set /a WINE_foo=WINE_bar -= WINE_bar + 7 & call :checkenvvars WINE_foo -7 WINE_bar -7
1412set WINE_bar=-7
1413set /a WINE_foo=WINE_bar /= 3 + 2 & call :checkenvvars WINE_foo -1 WINE_bar -1
1414set /a WINE_foo=WINE_bar=5, WINE_bar %%=2 & call :checkenvvars WINE_foo 5 WINE_bar 1
1415set WINE_bar=1
1416set /a WINE_foo=WINE_bar ^<^<= 2 & call :checkenvvars WINE_foo 4 WINE_bar 4
1417set WINE_bar=4
1418set /a WINE_foo=WINE_bar ^>^>= 2 & call :checkenvvars WINE_foo 1 WINE_bar 1
1419set WINE_bar=1
1420set /a WINE_foo=WINE_bar ^&= 2 & call :checkenvvars WINE_foo 0 WINE_bar 0
1421set /a WINE_foo=WINE_bar=5, WINE_bar ^|= 2 & call :checkenvvars WINE_foo 5 WINE_bar 7
1422set /a WINE_foo=WINE_bar=5, WINE_bar ^^= 2 & call :checkenvvars WINE_foo 5 WINE_bar 7
1423set WINE_baz=4
1424set /a WINE_foo=WINE_bar=19, WINE_bar %%= 4 + (WINE_baz %%= 7) & call :checkenvvars WINE_foo 19 WINE_bar 3 WINE_baz 4
1425echo --- quotes
1426set /a WINE_foo=1
1427call :checkenvvars WINE_foo 1
1428set /a "WINE_foo=1"
1429call :checkenvvars WINE_foo 1
1430set /a WINE_foo=1,WINE_bar=2
1431call :checkenvvars WINE_foo 1 WINE_bar 2
1432set /a "WINE_foo=1,WINE_bar=2"
1433call :checkenvvars WINE_foo 1 WINE_bar 2
1434set /a "WINE_foo=1","WINE_bar=2"
1435call :checkenvvars WINE_foo 1 WINE_bar 2
1436set /a ""WINE_foo=1","WINE_bar=2""
1437call :checkenvvars WINE_foo 1 WINE_bar 2
1438set /a WINE_foo=1,WINE_bar=2,WINE_baz=3
1439call :checkenvvars WINE_foo 1 WINE_bar 2 WINE_baz 3
1440set /a "WINE_foo=1,WINE_bar=2,WINE_baz=3"
1441call :checkenvvars WINE_foo 1 WINE_bar 2 WINE_baz 3
1442set /a "WINE_foo=1","WINE_bar=2","WINE_baz=3"
1443call :checkenvvars WINE_foo 1 WINE_bar 2 WINE_baz 3
1444set /a ""WINE_foo=1","WINE_bar=2","WINE_baz=3""
1445call :checkenvvars WINE_foo 1 WINE_bar 2 WINE_baz 3
1446set /a ""WINE_foo=1","WINE_bar=2"","WINE_baz=3"
1447call :checkenvvars WINE_foo 1 WINE_bar 2 WINE_baz 3
1448set /a """"""WINE_foo=1""""""
1449call :checkenvvars WINE_foo 1
1450set /a """"""WINE_foo=1","WINE_bar=5""","WINE_baz=2""
1451call :checkenvvars WINE_foo 1 WINE_bar 5 WINE_baz 2
1452set /a WINE_foo="3"+"4"+"5+6"
1453call :checkenvvars WINE_foo 18
1454set WINE_foo=3
1455set /a WINE_bar="WINE_""foo"+4
1456call :checkenvvars WINE_foo 3 WINE_bar 7
1457echo --- whitespace are ignored between double char operators
1458set WINE_foo=4
1459set WINE_bar=5
1460set /a     WINE_foo   +    = 6
1461set /a     WINE_bar     *    = WINE_foo
1462call :checkenvvars WINE_foo 10 WINE_bar 50
1463set WINE_foo=4
1464set WINE_bar=5
1465set /a     WINE_foo   +    = "6  < < 7"
1466set /a     WINE_bar     *    = WINE_foo  +  WINE_foo
1467call :checkenvvars WINE_foo 772 WINE_bar 7720
1468set /a     WINE_foo=6 7
1469set /a     WINE_ var1=8
1470set WINE_foo=
1471echo --- invalid operator sequence
1472set WINE_foo=4
1473set /a =4
1474set /a *=4
1475set /a ^>=4"
1476set /a ^<=4"
1477set /a WINE_foo^>^<=4
1478echo %WINE_foo%
1479set /a WINE_foo^>^>^>=4
1480echo %WINE_foo%
1481echo ----- negative prefix
1482set /a WINE_foo=-1
1483call :checkenvvars WINE_foo -1
1484set /a WINE_foo=--1
1485call :checkenvvars WINE_foo 1
1486set /a WINE_foo=3--3
1487call :checkenvvars WINE_foo 6
1488set /a WINE_foo=3---3
1489call :checkenvvars WINE_foo 0
1490set /a WINE_foo=3----3
1491call :checkenvvars WINE_foo 6
1492set /a WINE_foo=-~1
1493call :checkenvvars WINE_foo 2
1494set /a WINE_foo=~-1
1495call :checkenvvars WINE_foo 0
1496set /a WINE_foo=3+-~1
1497call :checkenvvars WINE_foo 5
1498set /a WINE_foo=3+~-1
1499call :checkenvvars WINE_foo 3
1500echo ----- assignment tests involving the end destination
1501set WINE_foo=3
1502set /a WINE_foo+=3+(WINE_foo=4)
1503call :checkenvvars WINE_foo 11
1504set WINE_foo=2
1505set /a WINE_bar=3+(WINE_foo=6)
1506call :checkenvvars WINE_foo 6 WINE_bar 9
1507set WINE_foo=2
1508set /a WINE_bar=3+(WINE_foo=6,WINE_baz=7)
1509call :checkenvvars WINE_foo 6 WINE_bar 10 WINE_baz 7
1510set WINE_foo=2
1511set /a WINE_bar=WINE_foo=7
1512call :checkenvvars WINE_foo 7 WINE_bar 7
1513echo ----- equal precedence on stack
1514rem Unary - don't reduce if precedence is equal
1515set /a WINE_foo=!!1
1516call :checkenvvars WINE_foo 1
1517set /a WINE_foo=!!0
1518call :checkenvvars WINE_foo 0
1519set /a WINE_foo=~~1
1520call :checkenvvars WINE_foo 1
1521set /a WINE_foo=~~0
1522call :checkenvvars WINE_foo 0
1523set /a WINE_foo=--1
1524call :checkenvvars WINE_foo 1
1525set /a WINE_foo=+-1
1526call :checkenvvars WINE_foo -1
1527set /a WINE_foo=-+1
1528call :checkenvvars WINE_foo -1
1529set /a WINE_foo=++1
1530call :checkenvvars WINE_foo 1
1531set /a WINE_foo=!~1
1532call :checkenvvars WINE_foo 0
1533set /a WINE_foo=~!1
1534call :checkenvvars WINE_foo -1
1535set /a WINE_foo=!-1
1536call :checkenvvars WINE_foo 0
1537set /a WINE_foo=-!1
1538call :checkenvvars WINE_foo 0
1539set /a WINE_foo=!-0
1540call :checkenvvars WINE_foo 1
1541set /a WINE_foo=-!0
1542call :checkenvvars WINE_foo -1
1543rem Aritmatic - Reduce if precedence is equal
1544set /a WINE_foo=10*5/2
1545call :checkenvvars WINE_foo 25
1546set /a WINE_foo=5/2*10
1547call :checkenvvars WINE_foo 20
1548set /a WINE_foo=10/5/2
1549call :checkenvvars WINE_foo 1
1550set /a WINE_foo=5%%2*4
1551call :checkenvvars WINE_foo 4
1552set /a WINE_foo=10-5+2
1553call :checkenvvars WINE_foo 7
1554set /a WINE_foo=1^<^<4^>^>1
1555call :checkenvvars WINE_foo 8
1556rem Assignment - don't reduce if precedence is equal
1557set /a WINE_foo=5
1558set /a WINE_bar=WINE_foo=6
1559call :checkenvvars WINE_foo 6 WINE_bar 6
1560
1561echo --- for /F
1562mkdir foobar & cd foobar
1563echo ------ string argument
1564rem NT4 does not support usebackq
1565for /F %%i in ("a b c") do echo %%i
1566for /f usebackq %%i in ('a b c') do echo %%i>output_file
1567if not exist output_file (echo no output) else (type output_file & del output_file)
1568for /f %%i in ("a ") do echo %%i
1569for /f usebackq %%i in ('a ') do echo %%i>output_file
1570if not exist output_file (echo no output) else (type output_file & del output_file)
1571for /f %%i in ("a") do echo %%i
1572for /f usebackq %%i in ('a') do echo %%i>output_file
1573if not exist output_file (echo no output) else (type output_file & del output_file)
1574fOr /f %%i in (" a") do echo %%i
1575for /f usebackq %%i in (' a') do echo %%i>output_file
1576if not exist output_file (echo no output) else (type output_file & del output_file)
1577for /f %%i in (" a ") do echo %%i
1578for /f usebackq %%i in (' a ') do echo %%i>output_file
1579if not exist output_file (echo no output) else (type output_file & del output_file)
1580echo ------ fileset argument
1581echo --------- basic blank handling
1582echo a b c>foo
1583for /f %%i in (foo) do echo %%i
1584echo a >foo
1585for /f %%i in (foo) do echo %%i
1586echo a>foo
1587for /f %%i in (foo) do echo %%i
1588echo  a>foo
1589for /f %%i in (foo) do echo %%i
1590echo  a >foo
1591for /f %%i in (foo) do echo %%i
1592echo. > foo
1593for /f %%i in (foo) do echo %%i
1594echo. >> foo
1595echo b > foo
1596for /f %%i in (foo) do echo %%i
1597echo --------- multi-line with empty lines
1598echo a Z f> foo
1599echo. >> foo
1600echo.>> foo
1601echo b bC>> foo
1602echo c>> foo
1603echo. >> foo
1604for /f %%b in (foo) do echo %%b
1605echo --------- multiple files
1606echo q w > bar
1607echo.>> bar
1608echo kkk>>bar
1609for /f %%k in (foo bar) do echo %%k
1610for /f %%k in (bar foo) do echo %%k
1611echo ------ command argument
1612rem Not implemented on NT4, need to skip it as no way to get output otherwise
1613if "%CD%"=="" goto :SkipFORFcmdNT4
1614for /f %%i in ('echo.Passed1') do echo %%i
1615for /f "usebackq" %%i in (`echo.Passed2`) do echo %%i
1616for /f usebackq %%i in (`echo.Passed3`) do echo %%i
1617goto :ContinueFORF
1618:SkipFORFcmdNT4
1619for /l %%i in (1,1,3) do echo Missing functionality - Broken%%i
1620:ContinueFORF
1621rem FIXME: Rest not testable right now in wine: not implemented and would need
1622rem preliminary grep-like program implementation (e.g. like findstr or fc) even
1623rem for a simple todo_wine test
1624rem (for /f "usebackq" %%i in (`echo z a b`) do echo %%i) || echo not supported
1625rem (for /f usebackq %%i in (`echo z a b`) do echo %%i) || echo not supported
1626echo ------ eol option
1627if "%CD%"=="" goto :SkipFORFeolNT4
1628echo Line one>foo
1629echo and Line two>>foo
1630echo Line three>>foo
1631for /f "eol=L" %%i in (foo) do echo %%i
1632for /f "eol=a" %%i in (foo) do echo %%i
1633del foo
1634goto :ContinueFORFeol
1635:SkipFORFeolNT4
1636for /l %%i in (1,1,3) do echo Broken NT4 functionality%%i
1637:ContinueFORFeol
1638for /f "eol=@" %%i in ("    ad") do echo %%i
1639for /f "eol=@" %%i in (" z@y") do echo %%i
1640for /f "eol=|" %%i in ("a|d") do echo %%i
1641for /f "eol=@" %%i in ("@y") do echo %%i > output_file
1642if not exist output_file (echo no output) else (del output_file)
1643for /f "eol==" %%i in ("=y") do echo %%i > output_file
1644if not exist output_file (echo no output) else (del output_file)
1645echo ------ delims option
1646for /f "delims=|" %%i in ("a|d") do echo %%i
1647for /f "delims=|" %%i in ("a |d") do echo %%i
1648for /f "delims=|" %%i in ("a d|") do echo %%i
1649for /f "delims=| " %%i in ("a d|") do echo %%i
1650for /f "delims==" %%i in ("C r=d|") do echo %%i
1651for /f "delims=" %%i in ("foo bar baz") do echo %%i
1652for /f "delims=" %%i in ("c:\foo bar baz\..") do echo %%~fi
1653echo ------ skip option
1654echo a > foo
1655echo b >> foo
1656echo c >> foo
1657for /f "skip=2" %%i in (foo) do echo %%i
1658for /f "skip=3" %%i in (foo) do echo %%i > output_file
1659if not exist output_file (echo no output) else (del output_file)
1660for /f "skip=4" %%i in (foo) do echo %%i > output_file
1661if not exist output_file (echo no output) else (del output_file)
1662for /f "skip=02" %%i in (foo) do echo %%i
1663for /f "skip=0x2" %%i in (foo) do echo %%i
1664for /f "skip=1" %%i in ("skipme") do echo %%i > output_file
1665if not exist output_file (echo no output) else (del output_file)
1666echo ------ tokens= option
1667rem Basic
1668for /f %%i in ("a b c d e f g") do echo h=%%h i=%%i j=%%j k=%%k l=%%l m=%%m o=%%o
1669for /f "tokens=2" %%i in ("a b c d e f g") do echo h=%%h i=%%i j=%%j k=%%k l=%%l m=%%m o=%%o
1670for /f "tokens=1,3,5-7" %%i in ("a b c d e f g") do echo h=%%h i=%%i j=%%j k=%%k l=%%l m=%%m o=%%o
1671rem Show * means the rest
1672for /f "tokens=1,5*" %%i in ("a b c d e f g") do echo h=%%h i=%%i j=%%j k=%%k l=%%l m=%%m o=%%o
1673for /f "tokens=6,9*" %%i in ("a b c d e f g h i j k l m n o p q r s t u v w x y z") do echo h=%%h i=%%i j=%%j k=%%k l=%%l m=%%m o=%%o
1674rem Show * means the rest (not tokenized and rebuilt)
1675for /f "tokens=6,9*" %%i in ("a b c d e f g h i j k l m  n;;==  o p q r s t u v w x y z") do echo h=%%h i=%%i j=%%j k=%%k l=%%l m=%%m o=%%o
1676rem Order is irrelevant
1677for /f "tokens=1,2,3*" %%i in ("a b c d e f g") do echo h=%%h i=%%i j=%%j k=%%k l=%%l m=%%m n=%%n o=%%o
1678for /f "tokens=3,2,1*" %%i in ("a b c d e f g") do echo h=%%h i=%%i j=%%j k=%%k l=%%l m=%%m n=%%n o=%%o
1679rem Duplicates are ignored
1680for /f "tokens=1,2,1*" %%i in ("a b c d e f g") do echo h=%%h i=%%i j=%%j k=%%k l=%%l m=%%m n=%%n o=%%o
1681rem Large tokens are allowed
1682for /f "tokens=25,1,5*" %%i in ("a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z") do echo h=%%h i=%%i j=%%j k=%%k l=%%l m=%%m n=%%n o=%%o
1683rem Show tokens blanked in advance regardless of uniqueness of requested tokens
1684for /f "tokens=1,1,1,2*" %%i in ("a b c d e f g") do echo h=%%h i=%%i j=%%j k=%%k l=%%l m=%%m n=%%n o=%%o
1685for /f "tokens=1-2,1-2,1-2" %%i in ("a b c d e f g") do echo h=%%h i=%%i j=%%j k=%%k l=%%l m=%%m n=%%n o=%%o
1686rem Show No wrapping from z to A BUT wrapping sort of occurs Z to a occurs
1687for /f "tokens=1-20" %%u in ("a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z") do echo u=%%u v=%%v w=%%w x=%%x y=%%y z=%%z A=%%A a=%%a
1688for /f "tokens=1-20" %%U in ("a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z") do echo U=%%U V=%%V W=%%W X=%%X Y=%%Y Z=%%Z A=%%A a=%%a
1689rem Show negative ranges have no effect
1690for /f "tokens=1-3,5" %%i in ("a b c d e f g") do echo h=%%h i=%%i j=%%j k=%%k l=%%l m=%%m o=%%o
1691for /f "tokens=3-1,5" %%i in ("a b c d e f g") do echo h=%%h i=%%i j=%%j k=%%k l=%%l m=%%m o=%%o
1692rem Show duplicates stop * from working
1693for /f "tokens=1,2,3*" %%i in ("a b c d e f g") do echo h=%%h i=%%i j=%%j k=%%k l=%%l m=%%m n=%%n o=%%o
1694for /f "tokens=1,1,3*" %%i in ("a b c d e f g") do echo h=%%h i=%%i j=%%j k=%%k l=%%l m=%%m n=%%n o=%%o
1695for /f "tokens=2,2,3*" %%i in ("a b c d e f g") do echo h=%%h i=%%i j=%%j k=%%k l=%%l m=%%m n=%%n o=%%o
1696for /f "tokens=3,2,3*" %%i in ("a b c d e f g") do echo h=%%h i=%%i j=%%j k=%%k l=%%l m=%%m n=%%n o=%%o
1697cd ..
1698rd /s/q foobar
1699echo ------ parameter splitting
1700echo forFParameterSplittingFunc "myparam1=myvalue1 myparam2=myparam2" mytest> foo
1701for /f "tokens=1 delims=;" %%i in (foo) do (call :%%i)
1702del foo
1703for /f "tokens=1 delims=;" %%i in ("forFParameterSplittingFunc "myparam1^=myvalue1 myparam2^=myparam2" mytest") do (call :%%i)
1704goto :forFParameterSplittingEnd
1705:forFParameterSplittingFunc
1706echo %~0 %~1 %~2 %~3 %~4 %~5
1707goto :eof
1708:forFParameterSplittingEnd
1709
1710echo ------------ Testing del ------------
1711echo abc > file
1712echo deleting 'file'
1713del file
1714if errorlevel 0 (
1715    echo errorlevel is 0, good
1716) else (
1717    echo unexpected errorlevel, got %errorlevel%
1718)
1719if not exist file (
1720    echo successfully deleted 'file'
1721) else (
1722    echo error deleting 'file'
1723)
1724echo attempting to delete 'file', even though it is not present
1725del file
1726if errorlevel 0 (
1727    echo errorlevel is 0, good
1728) else (
1729    echo unexpected errorlevel, got %errorlevel%
1730)
1731
1732echo ------------ Testing del /a ------------
1733del /f/q *.test > nul
1734echo r > r.test
1735attrib +r r.test
1736echo not-r > not-r.test
1737
1738if not exist not-r.test echo not-r.test not found before delete, bad
1739del /a:-r *.test
1740if not exist not-r.test echo not-r.test not found after delete, good
1741
1742if not exist r.test echo r.test not found before delete, bad
1743if exist r.test echo r.test found before delete, good
1744del /a:r *.test
1745if not exist r.test echo r.test not found after delete, good
1746if exist r.test echo r.test found after delete, bad
1747
1748echo ------------ Testing del /q ------------
1749mkdir del_q_dir
1750cd del_q_dir
1751echo abc > file1
1752echo abc > file2.dat
1753rem If /q doesn't work, cmd will prompt and the test case should hang
1754del /q * > nul
1755for %%a in (1 2.dat) do if exist file%%a echo del /q * failed on file%%a
1756for %%a in (1 2.dat) do if not exist file%%a echo del /q * succeeded on file%%a
1757cd ..
1758rmdir del_q_dir
1759
1760echo ------------ Testing del /s ------------
1761mkdir "foo bar"
1762cd "foo bar"
1763mkdir "foo:"
1764echo hi > file1.dat
1765echo there > file2.dat
1766echo bub > file3.dat
1767echo bye > "file with spaces.dat"
1768cd ..
1769del /s file1.dat > nul
1770del file2.dat /s > nul
1771del "file3.dat" /s > nul
1772del "file with spaces.dat" /s > nul
1773cd "foo bar"
1774for %%f in (1 2 3) do if exist file%%f.dat echo Del /s failed on file%%f
1775for %%f in (1 2 3) do if exist file%%f.dat del file%%f.dat
1776if exist "file with spaces.dat" echo Del /s failed on "file with spaces.dat"
1777if exist "file with spaces.dat" del "file with spaces.dat"
1778rmdir "foo:"
1779cd ..
1780rmdir "foo bar"
1781
1782echo ------------ Testing rename ------------
1783mkdir foobar & cd foobar
1784echo --- ren and rename are synonymous
1785echo > foo
1786rename foo bar
1787if exist foo echo foo should be renamed!
1788if exist bar echo foo renamed to bar
1789ren bar foo
1790if exist bar echo bar should be renamed!
1791if exist foo echo bar renamed to foo
1792echo --- name collision
1793echo foo>foo
1794echo bar>bar
1795ren foo bar 2> nul
1796type foo
1797type bar
1798rem no-op
1799ren foo foo
1800mkdir baz
1801ren foo baz\abc
1802echo --- rename read-only files
1803echo > file1
1804attrib +r file1
1805ren file1 file2
1806if not exist file1 (
1807    if exist file2 (
1808        echo read-only file renamed
1809    )
1810) else (
1811    echo read-only file not renamed!
1812)
1813echo --- rename directories
1814mkdir rep1
1815ren rep1 rep2
1816if not exist rep1 (
1817    if exist rep2 (
1818        echo dir renamed
1819    )
1820)
1821attrib +r rep2
1822ren rep2 rep1
1823if not exist rep2 (
1824    if exist rep1 (
1825        echo read-only dir renamed
1826    )
1827)
1828echo --- rename in other directory
1829if not exist baz\abc (
1830    echo rename impossible in other directory
1831    if exist foo echo original file still present
1832) else (
1833    echo shouldn't rename in other directory!
1834    if not exist foo echo original file not present anymore
1835)
1836cd .. & rd /s/q foobar
1837
1838echo ------------ Testing move ------------
1839mkdir foobar & cd foobar
1840echo --- file move
1841echo >foo
1842move foo bar > nul 2>&1
1843if not exist foo (
1844    if exist bar (
1845        echo file move succeeded
1846    )
1847)
1848echo bar>bar
1849echo baz> baz
1850move /Y bar baz > nul 2>&1
1851if not exist bar (
1852    if exist baz (
1853        echo file move with overwrite succeeded
1854    )
1855) else (
1856    echo file overwrite impossible!
1857    del bar
1858)
1859type baz
1860
1861attrib +r baz
1862move baz bazro > nul 2>&1
1863if not exist baz (
1864    if exist bazro (
1865        echo read-only files are moveable
1866        move bazro baz > nul 2>&1
1867    )
1868) else (
1869    echo read-only file not moved!
1870)
1871attrib -r baz
1872mkdir rep
1873move baz rep > nul 2>&1
1874if not exist baz (
1875    if exist rep\baz (
1876        echo file moved in subdirectory
1877    )
1878)
1879call :setError 0
1880move rep\baz . > nul 2>&1
1881move /Y baz baz > nul 2>&1
1882if errorlevel 1 (
1883    echo moving a file to itself should be a no-op!
1884) else (
1885    echo moving a file to itself is a no-op
1886)
1887echo ErrorLevel: %ErrorLevel%
1888call :setError 0
1889del baz
1890echo --- directory move
1891mkdir foo\bar
1892mkdir baz
1893echo baz2>baz\baz2
1894move baz foo\bar > nul 2>&1
1895if not exist baz (
1896    if exist foo\bar\baz\baz2 (
1897        echo simple directory move succeeded
1898    )
1899)
1900call :setError 0
1901mkdir baz
1902move baz baz > nul 2>&1
1903echo moving a directory to itself gives error; errlevel %ErrorLevel%
1904echo ------ dir in dir move
1905rd /s/q foo
1906mkdir foo bar
1907echo foo2>foo\foo2
1908echo bar2>bar\bar2
1909move foo bar > nul 2>&1
1910if not exist foo (
1911    if exist bar (
1912        dir /b /ad bar
1913        dir /b /a-d bar
1914        dir /b bar\foo
1915    )
1916)
1917cd .. & rd /s/q foobar
1918
1919echo ------------ Testing mkdir ------------
1920call :setError 0
1921echo --- md and mkdir are synonymous
1922mkdir foobar
1923echo %ErrorLevel%
1924rmdir foobar
1925md foobar
1926echo %ErrorLevel%
1927rmdir foobar
1928echo --- creating an already existing directory/file must fail
1929mkdir foobar
1930md foobar
1931echo %ErrorLevel%
1932rmdir foobar
1933echo > foobar
1934mkdir foobar
1935echo %ErrorLevel%
1936del foobar
1937echo --- multilevel path creation
1938mkdir foo
1939echo %ErrorLevel%
1940mkdir foo\bar\baz
1941echo %ErrorLevel%
1942cd foo
1943echo %ErrorLevel%
1944cd bar
1945echo %ErrorLevel%
1946cd baz
1947echo %ErrorLevel%
1948echo > ..\..\bar2
1949mkdir ..\..\..\foo\bar2
1950echo %ErrorLevel%
1951del ..\..\bar2
1952mkdir ..\..\..\foo\bar2
1953echo %ErrorLevel%
1954rmdir ..\..\..\foo\bar2
1955cd ..
1956rmdir baz
1957cd ..
1958rmdir bar
1959cd ..
1960rmdir foo
1961echo %ErrorLevel%
1962echo --- trailing backslashes
1963mkdir foo\\\\
1964echo %ErrorLevel%
1965if exist foo (rmdir foo & echo dir created
1966) else ( echo dir not created )
1967echo %ErrorLevel%
1968echo --- invalid chars
1969mkdir ?
1970echo mkdir ? gives errorlevel %ErrorLevel%
1971call :setError 0
1972mkdir ?\foo
1973echo mkdir ?\foo gives errorlevel %ErrorLevel%
1974call :setError 0
1975mkdir foo\?
1976echo mkdir foo\? gives errorlevel %ErrorLevel%
1977if exist foo (rmdir foo & echo ok, foo created
1978) else ( echo foo not created )
1979call :setError 0
1980mkdir foo\bar\?
1981echo mkdir foo\bar\? gives errorlevel %ErrorLevel%
1982call :setError 0
1983if not exist foo (
1984    echo bad, foo not created
1985) else (
1986    cd foo
1987    if exist bar (
1988        echo ok, foo\bar created
1989        rmdir bar
1990    )
1991    cd ..
1992    rmdir foo
1993)
1994echo --- multiple directories at once
1995mkdir foobaz & cd foobaz
1996mkdir foo bar\baz foobar "bazbaz" .\"zabzab"
1997if exist foo (echo foo created) else echo foo not created!
1998if exist bar (echo bar created) else echo bar not created!
1999if exist foobar (echo foobar created) else echo foobar not created!
2000if exist bar\baz (echo bar\baz created) else echo bar\baz not created!
2001if exist bazbaz (echo bazbaz created) else echo bazbaz not created!
2002if exist zabzab (echo zabzab created) else echo zabzab not created!
2003cd .. & rd /s/q foobaz
2004call :setError 0
2005mkdir foo\*
2006echo mkdir foo\* errorlevel %ErrorLevel%
2007if exist foo (rmdir foo & echo ok, foo created
2008) else ( echo bad, foo not created )
2009
2010echo ------------ Testing rmdir ------------
2011call :setError 0
2012rem rd and rmdir are synonymous
2013mkdir foobar
2014rmdir foobar
2015echo %ErrorLevel%
2016if not exist foobar echo dir removed
2017mkdir foobar
2018rd foobar
2019echo %ErrorLevel%
2020if not exist foobar echo dir removed
2021rem Removing nonexistent directory
2022rmdir foobar
2023echo %ErrorLevel%
2024rem Removing single-level directories
2025echo > foo
2026rmdir foo
2027echo %ErrorLevel%
2028if exist foo echo file not removed
2029del foo
2030mkdir foo
2031echo > foo\bar
2032rmdir foo
2033echo %ErrorLevel%
2034if exist foo echo non-empty dir not removed
2035del foo\bar
2036mkdir foo\bar
2037rmdir foo
2038echo %ErrorLevel%
2039if exist foo echo non-empty dir not removed
2040rmdir foo\bar
2041rmdir foo
2042rem Recursive rmdir
2043mkdir foo\bar\baz
2044rmdir /s /Q foo
2045if not exist foo (
2046    echo recursive rmdir succeeded
2047) else (
2048    rd foo\bar\baz
2049    rd foo\bar
2050    rd foo
2051)
2052mkdir foo\bar\baz
2053echo foo > foo\bar\brol
2054rmdir /s /Q foo 2>&1
2055if not exist foo (
2056    echo recursive rmdir succeeded
2057) else (
2058    rd foo\bar\baz
2059    del foo\bar\brol
2060    rd foo\bar
2061    rd foo
2062)
2063rem multiples directories at once
2064mkdir foobaz & cd foobaz
2065mkdir foo
2066mkdir bar\baz
2067mkdir foobar
2068rd /s/q foo bar foobar
2069if not exist foo (echo foo removed) else echo foo not removed!
2070if not exist bar (echo bar removed) else echo bar not removed!
2071if not exist foobar (echo foobar removed) else echo foobar not removed!
2072if not exist bar\baz (echo bar\baz removed) else echo bar\baz not removed!
2073cd .. & rd /s/q foobaz
2074
2075echo ------------ Testing pushd/popd ------------
2076cd
2077echo --- popd is no-op when dir stack is empty
2078popd
2079cd
2080echo --- pushing non-existing dir
2081pushd foobar
2082cd
2083echo --- basic behaviour
2084mkdir foobar\baz
2085pushd foobar
2086cd
2087popd
2088cd
2089pushd foobar
2090pushd baz
2091cd
2092popd
2093cd
2094pushd baz
2095popd
2096cd
2097popd
2098cd
2099pushd .
2100cd foobar\baz
2101pushd ..
2102cd
2103popd
2104popd
2105cd
2106rd /s/q foobar
2107
2108echo ------------ Testing attrib ------------
2109rem FIXME Add tests for archive, hidden and system attributes + mixed attributes modifications
2110mkdir foobar & cd foobar
2111echo foo original contents> foo
2112attrib foo
2113echo > bar
2114echo --- read-only attribute
2115rem Read-only files cannot be altered or deleted, unless forced
2116attrib +R foo
2117attrib foo
2118dir /Ar /B
2119echo bar>> foo
2120type foo
2121del foo > NUL 2>&1
2122if exist foo (
2123    echo Read-only file not deleted
2124) else (
2125    echo Should not delete read-only file!
2126)
2127del /F foo
2128if not exist foo (
2129    echo Read-only file forcibly deleted
2130) else (
2131    echo Should delete read-only file with del /F!
2132    attrib -r foo
2133    del foo
2134)
2135cd .. & rd /s/q foobar
2136echo --- recursive behaviour
2137mkdir foobar\baz & cd foobar
2138echo > level1
2139echo > whatever
2140echo > baz\level2
2141attrib baz\level2
2142cd ..
2143attrib +R l*vel? /S > nul 2>&1
2144cd foobar
2145attrib level1
2146attrib baz\level2
2147echo > bar
2148attrib bar
2149cd .. & rd /s/q foobar
2150echo --- folders processing
2151mkdir foobar
2152attrib foobar
2153cd foobar
2154mkdir baz
2155echo toto> baz\toto
2156attrib +r baz /s /d > nul 2>&1
2157attrib baz
2158attrib baz\toto
2159echo lulu>>baz\toto
2160type baz\toto
2161echo > baz\lala
2162rem Oddly windows allows file creation in a read-only directory...
2163if exist baz\lala (echo file created in read-only dir) else echo file not created
2164cd .. & rd /s/q foobar
2165
2166echo ------------ Testing assoc ------------
2167rem Modifying associations requires some privileges...
2168net session >nul 2>&1
2169if errorlevel 1 goto :SkipAssoc
2170
2171rem FIXME Can't test error messages in the current test system, so we have to use some kludges
2172rem FIXME Revise once || conditional execution is fixed
2173mkdir foobar & cd foobar
2174echo --- setting association
2175assoc .foo > baz
2176type baz
2177echo ---
2178
2179assoc .foo=bar
2180assoc .foo
2181
2182rem association set system-wide
2183echo @echo off> tmp.cmd
2184echo echo +++>> tmp.cmd
2185echo assoc .foo>> tmp.cmd
2186cmd /c tmp.cmd
2187
2188echo --- resetting association
2189assoc .foo=
2190assoc .foo > baz
2191type baz
2192echo ---
2193
2194rem association removal set system-wide
2195cmd /c tmp.cmd > baz
2196type baz
2197echo ---
2198cd .. & rd /s/q foobar
2199goto ContinueFType
2200:SkipAssoc
2201echo --- setting association
2202echo ---
2203echo .foo=bar
2204echo .foo=bar
2205echo +++
2206echo .foo=bar
2207echo --- resetting association
2208echo ---
2209echo +++
2210echo ---
2211
2212
2213:ContinueFType
2214echo ------------ Testing ftype ------------
2215rem Modifying associations requires some privileges...
2216net session >nul 2>&1
2217if errorlevel 1 goto :SkipFType
2218rem FIXME Can't test error messages in the current test system, so we have to use some kludges
2219rem FIXME Revise once || conditional execution is fixed
2220mkdir foobar & cd foobar
2221echo --- setting association
2222ftype footype> baz
2223type baz
2224echo ---
2225
2226ftype footype=foo_opencmd
2227assoc .foo=footype
2228ftype footype
2229
2230rem association set system-wide
2231echo @echo off> tmp.cmd
2232echo echo +++>> tmp.cmd
2233echo ftype footype>> tmp.cmd
2234cmd /c tmp.cmd
2235
2236echo --- resetting association
2237assoc .foo=
2238
2239rem Removing a file type association doesn't work on XP due to a bug, so a workaround is needed
2240setlocal EnableDelayedExpansion
2241set WINE_FOO=original value
2242ftype footype=
2243ftype footype > baz
2244for /F %%i in ('type baz') do (set WINE_FOO=buggyXP)
2245rem Resetting actually works on wine/NT4, but is reported as failing due to the peculiar test (and non-support for EnabledDelayedExpansion)
2246rem FIXME Revisit once a grep-like program like ftype is implemented
2247rem (e.g. to check baz's size using dir /b instead)
2248echo !WINE_FOO!
2249
2250rem cleanup registry
2251echo REGEDIT4> regCleanup.reg
2252echo.>> regCleanup.reg
2253echo [-HKEY_CLASSES_ROOT\footype]>> regCleanup.reg
2254regedit /s regCleanup.reg
2255set WINE_FOO=
2256endlocal
2257cd .. & rd /s/q foobar
2258goto ContinueCall
2259:SkipFType
2260echo --- setting association
2261echo ---
2262echo footype=foo_opencmd
2263echo .foo=footype
2264echo footype=foo_opencmd
2265echo +++
2266echo footype=foo_opencmd
2267echo --- resetting association
2268echo original value
2269
2270:ContinueCall
2271echo ------------ Testing CALL ------------
2272mkdir foobar & cd foobar
2273echo --- external script
2274echo echo foo %%1> foo.cmd
2275call foo
2276call foo.cmd 8
2277echo echo %%1 %%2 > foo.cmd
2278call foo.cmd foo
2279call foo.cmd foo bar
2280call foo.cmd foo ""
2281call foo.cmd "" bar
2282call foo.cmd foo ''
2283call foo.cmd '' bar
2284del foo.cmd
2285
2286echo --- internal routines
2287call :testRoutine :testRoutine
2288goto :endTestRoutine
2289:testRoutine
2290echo bar %1
2291goto :eof
2292:endTestRoutine
2293
2294call :testRoutineArgs foo
2295call :testRoutineArgs foo bar
2296call :testRoutineArgs foo ""
2297call :testRoutineArgs ""  bar
2298call :testRoutineArgs foo ''
2299call :testRoutineArgs ''  bar
2300goto :endTestRoutineArgs
2301:testRoutineArgs
2302echo %1 %2
2303goto :eof
2304:endTestRoutineArgs
2305
2306echo --- with builtins
2307call mkdir foo
2308echo %ErrorLevel%
2309if exist foo (echo foo created) else echo foo should exist!
2310rmdir foo
2311set WINE_FOOBAZ_VAR=foobaz
2312call echo Should expand %WINE_FOOBAZ_VAR%
2313set WINE_FOOBAZ_VAR=
2314echo>batfile
2315call dir /b
2316echo>robinfile
2317if 1==1 call del batfile
2318dir /b
2319if exist batfile echo batfile shouldn't exist
2320rem ... but not for 'if' or 'for'
2321call if 1==1 echo bar 2> nul
2322echo %ErrorLevel%
2323call :setError 0
2324call for %%i in (foo bar baz) do echo %%i 2> nul
2325echo %ErrorLevel%
2326rem First look for programs in the path before trying a builtin
2327echo echo non-builtin dir> dir.cmd
2328call dir /b
2329del dir.cmd
2330rem The below line equates to call (, which does nothing, then the
2331rem subsequent lines are executed.
2332call (
2333  echo Line one
2334  echo Line two
2335)
2336rem The below line equates to call if, which always fails, then the
2337rem subsequent lines are executed. Note cmd.exe swallows all lines
2338rem starting with )
2339call if 1==1 (
2340  echo Get if
2341) else (
2342  echo ... and else!
2343)
2344call call call echo passed
2345cd .. & rd /s/q foobar
2346
2347echo ------------ Testing SHIFT ------------
2348
2349call :shiftFun p1 p2 p3 p4 p5
2350goto :endShiftFun
2351
2352:shiftFun
2353echo '%1' '%2' '%3' '%4' '%5'
2354shift
2355echo '%1' '%2' '%3' '%4' '%5'
2356shift@tab@ /1
2357echo '%1' '%2' '%3' '%4' '%5'
2358shift /2
2359echo '%1' '%2' '%3' '%4' '%5'
2360shift /-1
2361echo '%1' '%2' '%3' '%4' '%5'
2362shift /0
2363echo '%1' '%2' '%3' '%4' '%5'
2364goto :eof
2365:endShiftFun
2366
2367echo ------------ Testing cmd invocation ------------
2368rem FIXME: only a stub ATM
2369echo --- a batch file can delete itself
2370echo del foo.cmd>foo.cmd
2371cmd /q /c foo.cmd
2372if not exist foo.cmd (
2373    echo file correctly deleted
2374) else (
2375    echo file should be deleted!
2376    del foo.cmd
2377)
2378echo --- a batch file can alter itself
2379echo echo bar^>foo.cmd>foo.cmd
2380cmd /q /c foo.cmd > NUL 2>&1
2381if exist foo.cmd (
2382    type foo.cmd
2383    del foo.cmd
2384) else (
2385    echo file not created!
2386)
2387
2388echo ---------- Testing copy
2389md foobar2
2390cd foobar2
2391rem Note echo adds 0x0d 0x0a on the end of the line in the file
2392echo AAA> file1
2393echo BBBBBB> file2
2394echo CCCCCCCCC> file3
2395md dir1
2396goto :testcopy
2397
2398:CheckExist
2399if exist "%1" (
2400  echo Passed: Found expected %1
2401) else (
2402  echo Failed: Did not find expected %1
2403)
2404del /q "%1" >nul 2>&1
2405shift
2406if not "%1"=="" goto :CheckExist
2407goto :eof
2408
2409:CheckNotExist
2410if not exist "%1" (
2411  echo Passed: Did not find %1
2412) else (
2413  echo Failed: Unexpectedly found %1
2414  del /q "%1" >nul 2>&1
2415)
2416shift
2417if not "%1"=="" goto :CheckNotExist
2418goto :eof
2419
2420rem Note: No way to check file size on NT4 so skip the test
2421:CheckFileSize
2422if not exist "%1" (
2423  echo Failed: File missing when requested filesize check [%2]
2424  goto :ContinueFileSizeChecks
2425)
2426for %%i in (%1) do set WINE_filesize=%%~zi
2427if "%WINE_filesize%"=="%2" (
2428    echo Passed: file size check on %1 [%WINE_filesize%]
2429) else (
2430  if "%WINE_filesize%"=="%%~zi" (
2431    echo Skipping file size check on NT4
2432  ) else (
2433    echo Failed: file size check on %1 [%WINE_filesize% != %2]
2434  )
2435)
2436:ContinueFileSizeChecks
2437shift
2438shift
2439if not "%1"=="" goto :CheckFileSize
2440goto :eof
2441
2442:testcopy
2443
2444rem -----------------------
2445rem Simple single file copy
2446rem -----------------------
2447rem Simple single file copy, normally used syntax
2448copy file1 dummy.file >nul 2>&1
2449if errorlevel 1 echo Incorrect errorlevel
2450call :CheckExist dummy.file
2451
2452rem Simple single file copy, destination supplied as two forms of directory
2453copy file1 dir1 >nul 2>&1
2454if errorlevel 1 echo Incorrect errorlevel
2455call :CheckExist dir1\file1
2456
2457copy file1 dir1\ >nul 2>&1
2458if errorlevel 1 echo Incorrect errorlevel
2459call :CheckExist dir1\file1
2460
2461rem Simple single file copy, destination supplied as fully qualified destination
2462copy file1 dir1\file99 >nul 2>&1
2463if errorlevel 1 echo Incorrect errorlevel
2464call :CheckExist dir1\file99
2465
2466rem Simple single file copy, destination not supplied
2467cd dir1
2468copy ..\file1 >nul 2>&1
2469if errorlevel 1 echo Incorrect errorlevel
2470call :CheckExist file1
2471cd ..
2472
2473rem Simple single file copy, destination supplied as nonexistent directory
2474copy file1 dir2\ >nul 2>&1
2475if not errorlevel 1 echo Incorrect errorlevel
2476call :CheckNotExist dir2 dir2\file1
2477
2478rem -----------------------
2479rem Wildcarded copy
2480rem -----------------------
2481rem Simple single file copy, destination supplied as two forms of directory
2482copy file? dir1 >nul 2>&1
2483if errorlevel 1 echo Incorrect errorlevel
2484call :CheckExist dir1\file1 dir1\file2 dir1\file3
2485
2486copy file* dir1\ >nul 2>&1
2487if errorlevel 1 echo Incorrect errorlevel
2488call :CheckExist dir1\file1 dir1\file2 dir1\file3
2489
2490rem Simple single file copy, destination not supplied
2491cd dir1
2492copy ..\file*.* >nul 2>&1
2493if errorlevel 1 echo Incorrect errorlevel
2494call :CheckExist file1 file2 file3
2495cd ..
2496
2497rem Simple wildcarded file copy, destination supplied as nonexistent directory
2498copy file? dir2\ >nul 2>&1
2499if not errorlevel 1 echo Incorrect errorlevel
2500call :CheckNotExist dir2 dir2\file1 dir2\file2 dir2\file3
2501
2502rem ------------------------------------------------
2503rem Confirm overwrite works (cannot test prompting!)
2504rem ------------------------------------------------
2505copy file1 testfile >nul 2>&1
2506copy /y file2 testfile >nul 2>&1
2507call :CheckExist testfile
2508
2509rem ------------------------------------------------
2510rem Test concatenation
2511rem ------------------------------------------------
2512rem simple case, no wildcards
2513copy file1+file2 testfile >nul 2>&1
2514if errorlevel 1 echo Incorrect errorlevel
2515call :CheckExist testfile
2516
2517rem simple case, wildcards, no concatenation
2518copy file* testfile >nul 2>&1
2519if errorlevel 1 echo Incorrect errorlevel
2520call :CheckExist testfile
2521
2522rem simple case, wildcards, and concatenation
2523echo ddddd > fred
2524copy file*+fred testfile >nul 2>&1
2525if errorlevel 1 echo Incorrect errorlevel
2526call :CheckExist testfile
2527
2528rem simple case, wildcards, and concatenation
2529copy fred+file* testfile >nul 2>&1
2530if errorlevel 1 echo Incorrect errorlevel
2531call :CheckExist testfile
2532
2533rem Calculate destination name
2534copy fred+file* dir1 >nul 2>&1
2535if errorlevel 1 echo Incorrect errorlevel
2536call :CheckExist dir1\fred
2537
2538rem Calculate destination name
2539copy fred+file* dir1\ >nul 2>&1
2540if errorlevel 1 echo Incorrect errorlevel
2541call :CheckExist dir1\fred
2542
2543rem Calculate destination name (none supplied)
2544cd dir1
2545copy ..\fred+..\file* >nul 2>&1
2546if errorlevel 1 echo Incorrect errorlevel
2547call :CheckExist fred
2548
2549copy ..\fr*+..\file1  >nul 2>&1
2550if errorlevel 1 echo Incorrect errorlevel
2551call :CheckExist fred
2552cd ..
2553
2554rem ******************************************************************
2555rem ASCII and BINARY tests
2556rem Note: hard coded numbers deliberate because need to ensure whether
2557rem an additional EOF has been added or not. There is no way to handle
2558rem EOFs in batch, so assume if a single byte appears, it's an EOF!
2559rem ******************************************************************
2560
2561rem Confirm original sizes of file1,2,3
2562call :CheckFileSize file1 5 file2 8 file3 11
2563
2564cd dir1
2565
2566rem ----------------------------------------------
2567rem Show concatenation defaults copy to ascii mode
2568rem ----------------------------------------------
2569rem Simple default copy source to destination (should not append EOF 5)
2570copy ..\file1 file1_default >nul 2>&1
2571call :CheckFileSize file1_default 5
2572
2573rem Simple binary copy source to destination (should not append EOF 5)
2574copy /b ..\file1 file1_default2 >nul 2>&1
2575call :CheckFileSize file1_default2 5
2576
2577rem Simple ascii copy source to destination (should append EOF 5+1, 8+1, 11+1)
2578copy /a ..\file1 file1_plus_eof >nul 2>&1
2579call :CheckFileSize file1_plus_eof 6
2580copy /a ..\file2 file2_plus_eof >nul 2>&1
2581call :CheckFileSize file2_plus_eof 9
2582copy /a ..\file3 file3_plus_eof >nul 2>&1
2583call :CheckFileSize file3_plus_eof 12
2584
2585rem Concat 2 files, ascii mode - (only one EOF on the end 5+8+1)
2586copy /a ..\file1+..\file2 file12_plus_eof >nul 2>&1
2587call :CheckFileSize file12_plus_eof 14
2588
2589rem Concat 2 files, binary mode - (no EOF on the end 5+8)
2590copy /b ..\file1+..\file2 file12_no_eof >nul 2>&1
2591call :CheckFileSize file12_no_eof 13
2592
2593rem Concat 2 files, default mode - (one EOF on the end 5+8+1)
2594copy ..\file1+..\file2 file12_eof2 >nul 2>&1
2595call :CheckFileSize file12_eof2 14
2596
2597rem Test copying when destination is one of the sources.
2598rem Concat file1+file2+file3 into file1, should produce file1+file2+file3 = 24
2599copy /y ..\file? .\ >nul 2>&1
2600copy /y /b file1+file2+file3 file1 >nul 2>&1
2601call :CheckFileSize file1 24
2602
2603rem Concat file1+file2+file3 into file2, should produce file1+file3 = 16
2604copy /y ..\file? .\ >nul 2>&1
2605copy /y /b file1+file2+file3 file2 >nul 2>&1
2606call :CheckFileSize file2 16
2607
2608rem Concat file1+file2+file3 into file3, should produce file1+file2 = 13
2609copy /y ..\file? .\ >nul 2>&1
2610copy /y /b file1+file2+file3 file3 >nul 2>&1
2611call :CheckFileSize file3 13
2612
2613rem --------------------------------------------------------------
2614rem Show ascii source copy stops at first EOF, binary does the lot
2615rem --------------------------------------------------------------
2616copy file1_plus_eof /b file1_binary_srccopy /b >nul 2>&1
2617call :CheckFileSize file1_binary_srccopy 6
2618
2619copy file1_plus_eof /a file1_ascii_srccopy /b >nul 2>&1
2620call :CheckFileSize file1_ascii_srccopy 5
2621
2622rem --------------------------------------------------------------
2623rem Show results of concatenating files (ending in EOFs) and /a /b
2624rem --------------------------------------------------------------
2625
2626rem Default and ascii copy reads as ascii, stripping EOFs, so 6-1 + 9-1 + 12-1 + 1
2627copy file1_plus_eof+file2_plus_eof+file3_plus_eof file123_default_copy >nul 2>&1
2628call :CheckFileSize file123_default_copy 25
2629copy /a file1_plus_eof+file2_plus_eof+file3_plus_eof file123_ascii_copy >nul 2>&1
2630call :CheckFileSize file123_ascii_copy 25
2631
2632rem In binary mode, we get 3 eofs, so 6 + 9 + 12 = 27
2633copy /b file1_plus_eof + file2_plus_eof + file3_plus_eof file123_binary_copy >nul 2>&1
2634call :CheckFileSize file123_binary_copy 27
2635
2636rem We can select which we want the eofs from by postfixing it with /a or /b
2637rem so here have first and third with eof, second as ascii 6 + 9-1 + 12
2638copy file1_plus_eof /b + file2_plus_eof /a + file3_plus_eof /b file123_mixed_copy1 >nul 2>&1
2639call :CheckFileSize file123_mixed_copy1 26
2640
2641rem By postfixing the destination with /a, we ask for an ascii destination which appends EOF
2642rem so here have first and third with eof, second as ascii 6 + 9-1 + 12 + extra EOF
2643rem Note the delta between this and the previous one also shows that the destination
2644rem ascii/binary is inherited from the last /a or /b on the line
2645copy file1_plus_eof /b + file2_plus_eof /a + file3_plus_eof /b file123_mixed_copy2 /a >nul 2>&1
2646call :CheckFileSize file123_mixed_copy2 27
2647
2648rem so here have second with eof, first and third as ascii 6-1 + 9 + 12-1
2649rem Note the delta between the next two also shows that the destination ascii/binary is
2650rem inherited from the last /a or /b on the line, so the first has an extra EOF
2651copy file1_plus_eof /a + file2_plus_eof /b + file3_plus_eof /a file123_mixed_copy3 >nul 2>&1
2652call :CheckFileSize file123_mixed_copy3 26
2653copy file1_plus_eof /a + file2_plus_eof /b + file3_plus_eof /a file123_mixed_copy4 /b >nul 2>&1
2654call :CheckFileSize file123_mixed_copy4 25
2655
2656rem -------------------------------------------------------------------------------------------
2657rem This shows when concatenating, an ascii destination always adds on an EOF but when we
2658rem are not concatenating, it's a direct copy regardless of destination if being read as binary
2659rem -------------------------------------------------------------------------------------------
2660
2661rem All 3 have eof's, plus an extra = 6 + 9 + 12 + eof
2662copy /b file1_plus_eof + file2_plus_eof + file3_plus_eof file123_mixed_copy5 /a >nul 2>&1
2663call :CheckFileSize file123_mixed_copy5 28
2664
2665rem All 2 have eof's, plus an extra = 6 + 12 + eof
2666copy /b file1_plus_eof + file3_plus_eof file123_mixed_copy6 /a >nul 2>&1
2667call :CheckFileSize file123_mixed_copy6 19
2668
2669rem One file has EOF, but doesn't get an extra one, i.e. 6
2670copy /b file1_plus_eof file123_mixed_copy7 /a >nul 2>&1
2671call :CheckFileSize file123_mixed_copy7 6
2672
2673rem Syntax means concatenate so ascii destination kicks in
2674copy /b file1_plus_eof* file123_mixed_copy8 /a >nul 2>&1
2675call :CheckFileSize file123_mixed_copy8 7
2676
2677del *.* /q
2678cd ..
2679
2680rem ---------------------------------------
2681rem Error combinations
2682rem ---------------------------------------
2683rem Specify source directory but name is a file
2684call :setError 0
2685copy file1\ dir1\ >NUL 2>&1
2686if errorlevel 1 echo Passed: errorlevel invalid check 1
2687if not errorlevel 1 echo Failed: errorlevel invalid check 1
2688call :CheckNotExist dir1\file1
2689
2690rem Overwrite same file
2691call :setError 0
2692copy file1 file1 >NUL 2>&1
2693if errorlevel 1 echo Passed: errorlevel invalid check 2
2694if not errorlevel 1 echo Failed: errorlevel invalid check 2
2695
2696rem Supply same file identified as a directory
2697call :setError 0
2698copy file1 file1\ >NUL 2>&1
2699if errorlevel 1 echo Passed: errorlevel invalid check 3
2700if not errorlevel 1 echo Failed: errorlevel invalid check 3
2701
2702cd ..
2703rd foobar2 /s /q
2704
2705echo ------------ Testing setlocal/endlocal ------------
2706call :setError 0
2707rem Note: setlocal EnableDelayedExpansion already tested in the variable delayed expansion test section
2708mkdir foobar & cd foobar
2709echo --- enable/disable extensions
2710setlocal DisableEXTensions
2711echo ErrLev: %ErrorLevel%
2712endlocal
2713echo ErrLev: %ErrorLevel%
2714echo @echo off> tmp.cmd
2715echo echo ErrLev: %%ErrorLevel%%>> tmp.cmd
2716rem Enabled by default
2717cmd /C tmp.cmd
2718cmd /E:OfF /C tmp.cmd
2719cmd /e:oN /C tmp.cmd
2720
2721rem FIXME: creating file before setting envvar value to prevent parsing-time evaluation (due to EnableDelayedExpansion not being implemented/available yet)
2722echo --- setlocal with corresponding endlocal
2723rem %CD% does not work on NT4 so use the following workaround
2724for /d %%i in (.) do set WINE_CURDIR=%%~dpnxi
2725echo @echo off> test.cmd
2726echo echo %%WINE_VAR%%>> test.cmd
2727echo setlocal>> test.cmd
2728echo set WINE_VAR=localval>> test.cmd
2729echo md foobar2>> test.cmd
2730echo cd foobar2>> test.cmd
2731echo echo %%WINE_VAR%%>> test.cmd
2732echo for /d %%%%i in (.) do echo %%%%~dpnxi>> test.cmd
2733echo endlocal>> test.cmd
2734echo echo %%WINE_VAR%%>> test.cmd
2735echo for /d %%%%i in (.) do echo %%%%~dpnxi>> test.cmd
2736set WINE_VAR=globalval
2737call test.cmd
2738echo %WINE_VAR%
2739for /d %%i in (.) do echo %%~dpnxi
2740cd /d %WINE_CURDIR%
2741rd foobar2
2742set WINE_VAR=
2743echo --- setlocal with no corresponding endlocal
2744echo @echo off> test.cmd
2745echo echo %%WINE_VAR%%>> test.cmd
2746echo setlocal>> test.cmd
2747echo set WINE_VAR=localval>> test.cmd
2748echo md foobar2>> test.cmd
2749echo cd foobar2>> test.cmd
2750echo echo %%WINE_VAR%%>> test.cmd
2751echo for /d %%%%i in (.) do echo %%%%~dpnxi>> test.cmd
2752set WINE_VAR=globalval
2753rem %CD% does not work on NT4 so use the following workaround
2754for /d %%i in (.) do set WINE_CURDIR=%%~dpnxi
2755call test.cmd
2756echo %WINE_VAR%
2757for /d %%i in (.) do echo %%~dpnxi
2758cd /d %WINE_CURDIR%
2759rd foobar2
2760set WINE_VAR=
2761echo --- setlocal within same batch program
2762set WINE_var1=one
2763set WINE_var2=
2764set WINE_var3=
2765rem %CD% does not work on NT4 so use the following workaround
2766for /d %%i in (.) do set WINE_CURDIR=%%~dpnxi
2767setlocal
2768set WINE_var2=two
2769mkdir foobar2
2770cd foobar2
2771setlocal
2772set WINE_var3=three
2773if "%WINE_var1%"=="one" echo Var1 ok 1
2774if "%WINE_var2%"=="two" echo Var2 ok 2
2775if "%WINE_var3%"=="three" echo Var3 ok 3
2776for /d %%i in (.) do set WINE_curdir2=%%~dpnxi
2777if "%WINE_curdir2%"=="%WINE_CURDIR%\foobar2" echo Directory is ok 1
2778endlocal
2779if "%WINE_var1%"=="one" echo Var1 ok 1
2780if "%WINE_var2%"=="two" echo Var2 ok 2
2781if "%WINE_var3%"=="" echo Var3 ok 3
2782for /d %%i in (.) do set WINE_curdir2=%%~dpnxi
2783if "%WINE_curdir2%"=="%WINE_CURDIR%\foobar2" echo Directory is ok 2
2784endlocal
2785if "%WINE_var1%"=="one" echo Var1 ok 1
2786if "%WINE_var2%"=="" echo Var2 ok 2
2787if "%WINE_var3%"=="" echo Var3 ok 3
2788for /d %%i in (.) do set WINE_curdir2=%%~dpnxi
2789if "%WINE_curdir2%"=="%WINE_CURDIR%" echo Directory is ok 3
2790rd foobar2 /s /q
2791set WINE_var1=
2792
2793echo --- Mismatched set and end locals
2794mkdir foodir2 2>nul
2795mkdir foodir3 2>nul
2796mkdir foodir4 2>nul
2797rem %CD% does not work on NT4 so use the following workaround
2798for /d %%i in (.) do set WINE_curdir=%%~dpnxi
2799
2800echo @echo off> 2set1end.cmd
2801echo echo %%WINE_var%%>> 2set1end.cmd
2802echo setlocal>> 2set1end.cmd
2803echo set WINE_VAR=2set1endvalue1>> 2set1end.cmd
2804echo cd ..\foodir3>> 2set1end.cmd
2805echo setlocal>> 2set1end.cmd
2806echo set WINE_VAR=2set1endvalue2>> 2set1end.cmd
2807echo cd ..\foodir4>> 2set1end.cmd
2808echo endlocal>> 2set1end.cmd
2809echo echo %%WINE_var%%>> 2set1end.cmd
2810echo for /d %%%%i in (.) do echo %%%%~dpnxi>> 2set1end.cmd
2811
2812echo @echo off> 1set2end.cmd
2813echo echo %%WINE_var%%>> 1set2end.cmd
2814echo setlocal>> 1set2end.cmd
2815echo set WINE_VAR=1set2endvalue1>> 1set2end.cmd
2816echo cd ..\foodir3>> 1set2end.cmd
2817echo endlocal>> 1set2end.cmd
2818echo echo %%WINE_var%%>> 1set2end.cmd
2819echo for /d %%%%i in (.) do echo %%%%~dpnxi>> 1set2end.cmd
2820echo endlocal>> 1set2end.cmd
2821echo echo %%WINE_var%%>> 1set2end.cmd
2822echo for /d %%%%i in (.) do echo %%%%~dpnxi>> 1set2end.cmd
2823
2824echo --- Extra setlocal in called batch
2825set WINE_VAR=value1
2826rem -- setlocal1 == this batch, should never be used inside a called routine
2827setlocal
2828set WINE_var=value2
2829cd foodir2
2830call "%WINE_CURDIR%\2set1end.cmd"
2831echo Finished:
2832echo %WINE_VAR%
2833for /d %%i in (.) do echo %%~dpnxi
2834endlocal
2835echo %WINE_VAR%
2836for /d %%i in (.) do echo %%~dpnxi
2837cd /d %WINE_CURDIR%
2838
2839echo --- Extra endlocal in called batch
2840set WINE_VAR=value1
2841rem -- setlocal1 == this batch, should never be used inside a called routine
2842setlocal
2843set WINE_var=value2
2844cd foodir2
2845call "%WINE_CURDIR%\1set2end.cmd"
2846echo Finished:
2847echo %WINE_VAR%
2848for /d %%i in (.) do echo %%~dpnxi
2849endlocal
2850echo %WINE_VAR%
2851for /d %%i in (.) do echo %%~dpnxi
2852cd /d %WINE_CURDIR%
2853
2854echo --- endlocal in called function rather than batch pgm is ineffective
2855@echo off
2856set WINE_var=1
2857set WINE_var2=1
2858setlocal
2859set WINE_var=2
2860call :endlocalroutine
2861echo %WINE_var%
2862endlocal
2863echo %WINE_var%
2864goto :endlocalfinished
2865:endlocalroutine
2866echo %WINE_var%
2867endlocal
2868echo %WINE_var%
2869setlocal
2870set WINE_var2=2
2871endlocal
2872echo %WINE_var2%
2873endlocal
2874echo %WINE_var%
2875echo %WINE_var2%
2876goto :eof
2877:endlocalfinished
2878echo %WINE_var%
2879
2880set WINE_var=
2881set WINE_var2=
2882cd .. & rd /q/s foobar
2883
2884echo ------------ Testing Errorlevel ------------
2885rem WARNING: Do *not* add tests using ErrorLevel after this section
2886should_not_exist 2> nul > nul
2887echo %ErrorLevel%
2888rem nt 4.0 doesn't really support a way of setting errorlevel, so this is weak
2889rem See http://www.robvanderwoude.com/exit.php
2890call :setError 1
2891echo %ErrorLevel%
2892if errorlevel 2 echo errorlevel too high, bad
2893if errorlevel 1 echo errorlevel just right, good
2894if errorlevel 01 echo errorlevel with leading zero just right, good
2895if errorlevel -1 echo errorlevel with negative number OK
2896if errorlevel 0x1 echo hexa should not be recognized!
2897if errorlevel 1a echo invalid error level recognized!
2898call :setError 0
2899echo abc%ErrorLevel%def
2900if errorlevel 1 echo errorlevel nonzero, bad
2901if not errorlevel 1 echo errorlevel zero, good
2902if not errorlevel 0x1 echo hexa should not be recognized!
2903if not errorlevel 1a echo invalid error level recognized!
2904rem Now verify that setting a real variable hides its magic variable
2905set errorlevel=7
2906echo %ErrorLevel% should be 7
2907if errorlevel 7 echo setting var worked too well, bad
2908call :setError 3
2909echo %ErrorLevel% should still be 7
2910
2911echo ------------ Testing GOTO ------------
2912if a==a goto dest1
2913echo FAILURE at dest 1
2914:dest1
2915echo goto with no leading space worked
2916if a==a goto :dest1b
2917echo FAILURE at dest 1b
2918:dest1b
2919echo goto with colon and no leading space worked
2920if b==b goto dest2
2921echo FAILURE at dest 2
2922 :dest2
2923echo goto with a leading space worked
2924if c==c goto dest3
2925echo FAILURE at dest 3
2926	:dest3
2927echo goto with a leading tab worked
2928if d==d goto dest4
2929echo FAILURE at dest 4
2930:dest4@space@
2931echo goto with a following space worked
2932if e==e goto dest5
2933echo FAILURE at dest 5
2934:dest5&& echo FAILURE
2935echo goto with following amphersands worked
2936
2937del failure.txt >nul 2>&1
2938if f==f goto dest6
2939echo FAILURE at dest 6
2940:dest6>FAILURE.TXT
2941if exist FAILURE.TXT echo FAILURE at dest 6 as file exists
2942echo goto with redirections worked
2943del FAILURE.TXT >nul 2>&1
2944
2945:: some text that is ignored | dir >cmd_output | another test
2946if exist cmd_output echo FAILURE at dest 6 as file exists
2947echo Ignoring double colons worked
2948del cmd_output >nul 2>&1
2949
2950rem goto a label which does not exist issues an error message and
2951rem acts the same as goto :EOF, and ensure ::label is never matched
2952del testgoto.bat >nul 2>&1
2953echo goto :dest7 ^>nul 2^>^&1 >> testgoto.bat
2954echo echo FAILURE at dest 7 - Should have not found label and issued an error plus ended the batch>> testgoto.bat
2955echo ::dest7>> testgoto.bat
2956echo echo FAILURE at dest 7 - Incorrectly went to label >> testgoto.bat
2957call testgoto.bat
2958del testgoto.bat >nul 2>&1
2959
2960del testgoto.bat >nul 2>&1
2961echo goto ::dest8 ^>nul 2^>^&1 >> testgoto.bat
2962echo echo FAILURE at dest 8 - Should have not found label and issued an error plus ended the batch>> testgoto.bat
2963echo ::dest8>> testgoto.bat
2964echo echo FAILURE at dest 8 - Incorrectly went to label >> testgoto.bat
2965call testgoto.bat
2966del testgoto.bat >nul 2>&1
2967
2968if g==g goto dest9
2969echo FAILURE at dest 9
2970:dest91
2971echo FAILURE at dest 91
2972@   :     dest9>rubbish
2973echo label with mixed whitespace and no echo worked
2974
2975if h==h goto :dest10:this is ignored
2976echo FAILURE at dest 10
2977:dest10:this is also ignored
2978echo Correctly ignored trailing information
2979
2980echo ------------ Testing PATH ------------
2981set WINE_backup_path=%path%
2982set path=original
2983path
2984path try2
2985path
2986path=try3
2987path
2988set path=%WINE_backup_path%
2989set WINE_backup_path=
2990
2991echo ------------ Testing combined CALLs/GOTOs ------------
2992echo @echo off>foo.cmd
2993echo goto :eof>>foot.cmd
2994echo :eof>>foot.cmd
2995echo echo world>>foo.cmd
2996
2997echo @echo off>foot.cmd
2998echo echo cheball>>foot.cmd
2999echo.>>foot.cmd
3000echo call :bar>>foot.cmd
3001echo if "%%1"=="deleteMe" (del foot.cmd)>>foot.cmd
3002echo goto :eof>>foot.cmd
3003echo.>>foot.cmd
3004echo :bar>>foot.cmd
3005echo echo barbare>>foot.cmd
3006echo goto :eof>>foot.cmd
3007
3008call foo.cmd
3009call foot
3010call :bar
3011del foo.cmd
3012rem Script execution stops after the following line
3013foot deleteMe
3014call :foo
3015call :foot
3016goto :endFuns
3017
3018:foot
3019echo foot
3020
3021:foo
3022echo foo
3023goto :eof
3024
3025:endFuns
3026
3027:bar
3028echo bar
3029call :foo
3030
3031:baz
3032echo baz
3033goto :eof
3034
3035echo Final message is not output since earlier 'foot' processing stops script execution
3036echo Do NOT add any tests below this line
3037
3038echo ------------ Done, jumping to EOF -----------
3039goto :eof
3040rem Subroutine to set errorlevel and return
3041rem in windows nt 4.0, this always sets errorlevel 1, since /b isn't supported
3042:setError
3043exit /B %1
3044rem This line runs under cmd in windows NT 4, but not in more modern versions.
3045