☺?♥♠a♀???☻?☻ for weirdness ♠☺??↨??$error = 7 niet vinden.

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: ☺?♥♠a♀???☻?☻ for weirdness ♠☺??↨??$error = 7 niet vind

#16 Post by Ed Dyreen » 16 Jul 2011 09:08

'
XP uses cmd v2, more recent versions use v3.
I've run my macros against XP's ServicePack3, bad news though, the bug still pops up. :x

But I succesfully worked around the problem for macros that are called directly 8)

Code: Select all

set "@forU=set "?=" &( for %%^^^! in"

set "@Udelim=do set "?=^^^!?^^^!¦%%^^^!" ) &set "?=^^^!?:*¦=^^^!" &set "?=^^^!?:~1,-1^^^!" &for /f "tokens=1-26 delims=¦" %%a in ( "^^^!?^^^!" ) do"
::
%@forU% ( '$Debug, "This Works"' ) %@Udelim% echo. a=%%a_ &echo. b=%%b_

set ^"@PushArray=!@Udelim! ( %$n1c%
   echo. a=%%a_ %$n1c%
   echo. b=%%b_ %$n1c%
)"
::
%@forU% ( '$Debug, "This Works"' ) %@PushArray%
I figured I don't need echo to avoid the problem, It also works with a rem statement, I now use this command "rem .çommas":

I tried to work around the problem for macros that are called indirectly, and I succeeded in 95% of the cases,
too bad it don't work ALL the time.

Code: Select all

::--------------------------------------------------------------------------------------------------------------------------
::
:: exec any external command v initialize functions
::
::(
	set "$DefinedFLAG=%*"
	::
	if defined @DdefEcho (

		%@DequEcho% star        : '%*'
		%@DequEcho% $DefinedFLAG: '%$DefinedFLAG%'
	)
	::
	if defined $DefinedFLAG (

		%@forTS% ( "%~1" ) %@TraceIn%

		rem .çommas
		call :%$DefinedFLAG%
		rem .çommas
		%@DequPause%

		%@TraceOut%
		exit /b !$error!
	)
::
goto :skip "()"
%@endoftest%
:skip ()
::)
::--------------------------------------------------------------------------------------------------------------------------

::--------------------------------------------------------------------------------------------------------------------------
%@Pre% §Functions
::(

::--------------------------------------------------------------------------------------------------------------------------
set "$Defines=§CallMacro"
::
	set ^"$Usage.%$Defines%=^
%	% Usage: %%@forEL%% ( 'r$for, o$Macro o?params' ) %%@CallMacro%% %$n1c%
%	% input: %$n1c%
%	%  r$for   : supports simple for's, complex: @forU, @forEL %$n1c%
%	%  o$Macro : Name of macro that will be executed %$n1c%
%	%  o?params: Parameters to pass to macro that will be executed %$n1c%
%	% ToConsole: %$n1c%
%	%  None: the output cannot be redirected. %$n1c%
%	% Return: %$n1c%
%	%  $error: from called macro. "
::
goto :skip "()"
::
:: Do not remove the "rem .çommas" lines, they prevent the for çommas bug/annoyance on XP !
::
:§CallMacro "()"
::(
	rem %@Ddef% set "$Debug.Sub=!$Trace!"
	::
	Setlocal EnableDelayedExpansion 				%=Prevent variable conflicts with caller=%

	set "$param=%*"
	::
	%@DequForE% ( "$param=!$param!_" ) %@21necho_#AsDLT%

	if ["!$param:~0,1!"] == [""^"] if ["!$param:~-1!"] == [""^"] set "$param=!$param:~1,-1!"
	if defined $param set "$param=!$param:?=i!" %$n1c%
	::
	%@DequForT% ( "" "process $param:" ) %@21necho_#AsDLT%
	%@DequForE% ( "$param=!$param!_" ) %@21necho_#AsDLT%

	%@DequForT% ( "" "split $for, $macro, $param:" ) %@21necho_#AsDLT%
	::
	set "$for="
	set "$macro="
	set /a $trigger = 0
	::
	%@forTS% (

		!$param!

	) do 	if defined $for ( 					%=Declare $for=%
		::
		if defined $macro ( 					%=Declare $macro=%
			::
			if !$trigger! equ 0 ( 				%=Declare $param=%
				::
				set "$param=%%!"
				::
				set /a $trigger = 1

			) else 	set "$param=!$param! %%!"

		) else 	set "$macro=%%~!"

	) else 	set "$for=%%~!"
	::
	if not defined $macro (
		::
		set /a $Direct = 1
		::
		set "$param="

	) else 	set /a $Direct = 0
	::
	%@DequForE% ( "$for=!$for!_" ) %@21necho_#AsDLT%
	%@DequForE% ( "$macro=!$macro!_" ) %@21necho_#AsDLT%
	%@DequForE% ( "$param=!$param!_" ) %@21necho_#AsDLT%
	%@DequPause%

	set /a $delims = 0

	%@DequForT% ( "" "split @forU $param;" ) %@21necho_#AsDLT% 	%=split @forU $param;=%
	::
	if /i ["!$for!"] == ["@forU"] (
		::
		set /a $trigger = 0
		::
		%@forTS% (

			!$param!

		) do 	if !$trigger! equ 0 ( 				%=Declare $param=%
			::
			set "$param=%%!"
			::
			set /a $trigger = 1

		) else 	set "$param=!$param!, %%!"
		::
		set /a $delims = 1

	) else 	if /i ["!$for!"] == ["@forEL"] (
		::
		set /a $delims = 1
	)

	%@DequForT% ( "" "split for $delims;" ) %@21necho_#AsDLT% 	%=split @for $delims;=%
	if !$delims! equ 1 (
		::
		set "$param='!$param!'"

	) else 	set  $param="!$param!"

	%@DequForT% ( "eval $for;" ) %@21necho_#AsDLT% 			%=eval ( $for )=%
	::
	for %%! in ( "%$for%" ) do set "$for=!%%~!!"

	%@DequForT% ( "eval $macro;" ) %@21necho_#AsDLT% 		%=eval ( $macro )=%
	::
	if !$Direct! equ 1 (
		::
		set "$macro=!$for!"
		::
		set "$for="

	) else	for %%! in (

		"%$macro%"

	) do 	set "$macro=!%%~!!"
	::
	%@DequForE% ( "$Direct=!$Direct!_" ) %@21necho_#AsDLT%
	%@DequForE% ( "$macro=!$macro!_" ) %@21necho_#AsDLT%
	%@DequForE% ( "$for=!$for!_" ) %@21necho_#AsDLT%
	%@DequForE% ( "$param=!$param!_" ) %@21necho_#AsDLT%

	rem .çommas
	:breakif () 							%=InDirect call=%
	::(
		if %$Direct% neq 0 goto :breakif "()"
		::
		rem .çommas
		%@DdefEcho% !$for! ( !$param! ) %%$macro%% &%@pause%
		::
		(
			Endlocal
			rem .çommas çommas çommas
			%$for% ( %$param% ) %$macro%
			rem .çommas çommas çommas
		)
		::
		%@DequForT% ( "returned from indirect" ) %@21necho_#AsDLT%
		%@DequPause%
		rem .çommas
	::
	goto :fin "()"
	::)

	:breakif () 							%=Direct call=%
	::(
		%@DdefEcho% %%$macro%% &%@pause%
		::
		(
			Endlocal

			%$macro%
		)
		::
		%@DequForT% ( "returned from direct" ) %@21necho_#AsDLT%
		%@DequPause%
	::
	:fin ()
	::)
	rem .çommas
::
exit /b !$error!
::
call :§CallMacro "()"
:skip ()
::)
::--------------------------------------------------------------------------------------------------------------------------
I call into it using this macro:

Code: Select all

::--------------------------------------------------------------------------------------------------------------------------
set "$Defines=@CallMacro" &set "$Details="
::
:: calls a function §CallMacro that calls a macro, use as a breakpoint for macros that would otherwise pass the 8k limit
::
2>%@DNul% ( %@forA% ( '"%$Defines%"¦"EnableDelayedExpansion"' ) %@Macro.Begin% )
::(
	set ^"$Usage.%$Defines%=^
%	% Usage: %%@forEL%% ( 'r$for, o$Macro, o?params' ) %%@CallMacro%% %$n1c%
%	% input: %$n1c%
%	%  r$for   : only supports looptokens like @forEL, @forU, @forTS %$n1c%
%	%  r$Macro : Name of macro that will be executed %$n1c%
%	%  o?params: Parameters to pass to macro that will be executed %$n1c%
%	% ToConsole: None %$n1c%
%	% Return: %$n1c%
%	%  $error: from called macro. "
	::
	set ^"%$Defines%=do ( call "^!$UDF.FullPathFile^!" §CallMacro "%%~^!" )"
	::
	%@forEL% ( '@forU, @TestforUmacro, $This, "$Works", "This=Working"' ) %@CallMacro%
	%@forEL% ( '@Delayed' ) %@CallMacro%
::)
2>%@DNul% %@Macro.End%
::
%@COMMIT%
::--------------------------------------------------------------------------------------------------------------------------
::
goto :skip "()"
%@endoftest%
:skip ()
And this is a macro that uses it and sometimes encounters the bug:

Code: Select all

::--------------------------------------------------------------------------------------------------------------------------
set "$Defines=@Move.Object" &set "$Details=Move a previously declared object"
::
2>%@DNul% ( %@forA% ( '"%$Defines%"¦"EnableDelayedExpansion"' ) %@Macro.Begin% )
::(
	set ^"$Usage.%$Defines%=^
%	% Usage: %%@forU%% ( 'r#Name, r?NewLocation, o#error.bool' ) %%%$Defines%%% %$n1c%
%	% input: %$n1c%
%	%  r#Name       : Name of object %$n1c%
%	%  r?NewLocation: New physicall location of object %$n1c%
%	%  o#error.bool : 0 for always return, 1 for always PANIC %$n1c%
%	% ToConsole     : Contents of $Name %$n1c%
%	% Return: %$n1c%
%	%  $error: 0 for succes, 1 for error "
	::
%	% set ^"%$Defines%=!@Udelim! ( %$n1c%
%		% 					%=if defined $Debug.Sub set "$Debug.Sub=!$Defines!"=% %$n1c%
%		% !@forEL! ( '@forEL, @LeadIn, %$Defines%, "r#Name=%%~a", "r?NewLocation=%%~b", "o#error.bool=%%~c"' ) !@CallMacro! %$n1c%

%		% !@forEL! ( '@forU, @Object.Chk.Exist, "^!$Name^!", "^!$error.bool^!"' ) !@CallMacro! ^>nul %$n1c%
%		% !@forU! ( '"^!$Name^!"' ) !@Object.Extend! ^>nul %$n1c%
%		% !@n2echo! %$Defines%: '^^^!$Name^^^!' '^^^!$Extension^^^!' %$n1c%
%		% if ^^^!$error^^^! equ 0 if /i ["^!$Extension^!"] == ["AsDir"] ( %$n1c%

%		% 	!@forEL! ( '@forU, @Move.AsDir, "^!$Name^!", $NewLocation, "^!$error.bool^!"' ) !@CallMacro! %$n1c%

%		% ) else if /i ["^!$Extension^!"] == ["AsFile"] ( %$n1c%

%		% 	!@forEL! ( '@forU, @Move.AsFile, "^!$Name^!", $NewLocation, "^!$error.bool^!"' ) !@CallMacro! %$n1c%

%		% ) %$n1c%

%		% !@IfErrorBoolExit! %$n1c%
%		% !@nError! %$n1c%
%		% !@LeadOut! %$n1c%
%	% )"
::)
2>%@DNul% %@Macro.End%
::
%@COMMIT%
::
%@forU% ( '$aFile, "C:\This Works\This Works\This Works.TMP", 1' ) %@Move.Object%
%@forU% ( '$aDir, "C:\This Works", 1' ) %@Move.Object%
::--------------------------------------------------------------------------------------------------------------------------
::
goto :skip "()"
%@endoftest%
:skip ()
I'm sorry it's big &obfuscated, but I hope it gives the experts an idea of what I'm trying to achieve. I wish I could post a SMALL example, the problem is, this behavior only occurs with complex macros :(
OUTPUT:

Code: Select all

 >> Pre Define @Move.Object, Move a previously declared object
 << Post Define @Move.Object, Move a previously declared object [OK]

 @Move.Object: '$aFile' 'AsFile'

 @Move.AsFile: '$aFile' 'AsFile'
  $FullPathFile.OLD: 'C:\This Works\This Works.TMP'
  $FullPathFile.NEW: 'C:\This Works\This Works\This Works.TMP'
 [ok:0]
 [ok:0]

 @Move.Object: '$aDir' 'AsDir' Kan bestand bool%▬♦ niet vinden.


 @Move.AsDir: '$aDir' 'AsDir'
  $FullPath.OLD: 'C:\This_Works'
  $FullPath.NEW: 'C:\This Works'
0 bestand(en) gekopieerd
 [ok:0]
 [ok:0]
 endoftest Druk op een toets om door te gaan. . .
Don't ask me why or how, I have absolutely no idea what I'm dooing. :?

If someone want's to see the bug in action using the full sourcecode,
browse to scriptingpros and download the "Pre release" attachment at the bottom of the page if it's there,
otherwise download the release version...
http://www.scriptingpros.com/viewtopic.php?f=152&t=70

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: ☺?♥♠a♀???☻?☻ for weirdness ♠☺??↨??$error = 7 niet vind

#17 Post by dbenham » 17 Jul 2011 13:02

jeb wrote:Sometimes the parser seems to be unsure what is a text and what is a file.

Code: Select all

FOR /f "delims=" %%a in ("one two" ) do echo %%a
FOR /f "delims=" %%a in ("one two" three   ) do echo %%a
output wrote:one two
The file "one two" three" can't be found.


Very interesting - I think you are on to something.
Although the error message I am getting is slightly different (it makes the results even more suspicious):

Code: Select all

The system cannot find the file one two" three.


@Ed
Ed - even if you manage to eliminate the error message in all cases on your machine, I would worry that if you take the code to another machine, it might resurrect itself. We have already seen evidence that the bug shows up with different frequencies on different machines.

I think the only sure fix is a fixed CMD.EXE.

I would worry about taking CMD.EXE from a different version of Windows. Assuming that it works at all, would you ever be confident it works in all situations?

Dave Benham

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: ☺?♥♠a♀???☻?☻ for weirdness ♠☺??↨??$error = 7 niet vind

#18 Post by dbenham » 17 Jul 2011 14:33

Continuing with jeb's line of thought concerning a confused parser:

Code: Select all

@echo off
echo file1 content>file1.txt
echo file2 content>file2.txt

for /f "delims=" %%a in (
  file1.txt
  file2.txt
  "file1.txt file2.txt"
  file1.txt
  file2.txt
) do echo %%a

Output on Vista:

Code: Select all

file1 content
file2 content
file1.txt file2.txt
One FOR /F command can clearly processes both files AND a text string :!:
But it does not resume file processing once the text string is encountered.

Output on XP:

Code: Select all

file1 content
file2 content
file1.txt file2.txt
The system cannot find the file ile1.txt.
:shock: I think we have found the crux of the XP bug :!:
XP continues processing after the string is found, but not in a healthy way.

Dave Benham

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: ☺?♥♠a♀???☻?☻ for weirdness ♠☺??↨??$error = 7 niet vind

#19 Post by Ed Dyreen » 17 Jul 2011 14:57

I believe I can work around it some day from now.
My workaround for macros that are called directly really does work all the time simply because it avoids the problem.
I should be able to use the same technique for indirect calls. :)

You are right about grabbing a different CMD, it would be a total panic reaction and will only lead to more problems...

I believe you when you say it could be a pointer problem,
especially because the behavior can be influenced by unrelated commands like rem and echo. They help, but it's not the solution.

... Here we go again ... DOS ... stands for one problem after another, when is it going to stop
aargh I'm pulling my hairs out (the ones I have left).
XP continues processing after the string is found, but not in a healthy way.
Did you run my macro's ?, I often get a beep from my internal speaker ??
Who the hell told it do an <nul set /p "=" ?? Weird...
I'm not giving up, I've come too far...

Interesting, this dude has decompiled CMD with IDA...
O man, I really need to extend my knowhow...
http://www.remkoweijnen.nl/blog/2011/02 ... mpt-patch/
I tried server 2003's CMD.EXE on XP, but would need to replace the kernell32.dll to make it work.
I tried vista's CMD.EXE on XP, but it's not a valid 32bit application ???, weird...
Last edited by Ed Dyreen on 18 Jul 2011 07:33, edited 11 times in total.

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: ☺?♥♠a♀???☻?☻ for weirdness ♠☺??↨??$error = 7 niet vind

#20 Post by dbenham » 17 Jul 2011 15:37

Ed Dyreen wrote:I often get a beep from my internal speaker ??

Since the error message is random gibberish, it doesn't surprise me that sometimes the error message includes a <Ctrl>G (0x07)

Dave Benham

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: ☺?♥♠a♀???☻?☻ for weirdness ♠☺??↨??$error = 7 niet vind

#21 Post by dbenham » 23 Jul 2011 16:26

@Ed, regarding post at the top of this page dated 16 Jul 2011 10:08

1) In your bug workaround, why enclose the IN() clause in single quotes? Your @forU simple FOR loop does not use the single quotes, and then you strip them off later anyway.

This code:

Code: Select all

set "@Udelim=do set "?=^^^!?^^^!¦%%^^^!" ) &set "?=^^^!?:*¦=^^^!" &set "?=^^^!?:~1,-1^^^!" &for /f "tokens=1-26 delims=¦" %%a in ( "^^^!?^^^!" ) do"
::
%@forU% ( '$Debug, "This Works"' ) %@Udelim% echo. a=%%a_ &echo. b=%%b_

Can be simplified to this:

Code: Select all

set "@Udelim=do set "?=^^^!?^^^!¦%%^^^!" ) &set "?=^^^!?:*¦=^^^!" &for /f "tokens=1-26 delims=¦" %%a in ( "^^^!?^^^!" ) do"
::
%@forU% ( $Debug, "This Works" ) %@Udelim% echo. a=%%a_ &echo. b=%%b_

I think the idea of using a simple FOR instead of FOR /F has potential. I have been toying around with this concept as well. More on this later.


2) I don't understand what you gain with your @CallMacro macro. Why call a complex macro to call your §CallMacro function when you can call the function directly? I suppose you can say your macro code is "pure" in that it doesn't directly call a function except in this one place. But that seems purely academic and counter-productive.

You could easily create a simple macro that makes the function call very concise. Something like:

Code: Select all

set CallMacroViaFunction=call "%$UDF.FullPathFile%" §CallMacro
I'm sure you would have your own naming style, etc. But the concept is solid.

Then to call the macro you would simply:

Code: Select all

%CallMacroViaFunction% @MacroName Arg1 Arg2 Arg3
You should be able to use this type of code anywhere, including inside a macro.

I generally understand your §CallMacro function, but there are a lot of details that I haven't been able to parse through.


Regarding the rest:
Ed Dyreen wrote:I'm sorry it's big &obfuscated
That is an understatement. Your project is so large and interconnected, it is very hard to digest a small piece. I imagine there are ideas embedded in your code base that I would appreciate, but they are too difficult to find. It's even worse trying to find solutions to any problems that may be within.

Dave Benham

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: ☺?♥♠a♀???☻?☻ for weirdness ♠☺??↨??$error = 7 niet vind

#22 Post by Ed Dyreen » 23 Jul 2011 16:39

'
I'm a little busy at the moment, I'll give it a thought :D
Thanx,

Another issue is that the macros need to be loaded in a specific order for it to work interconnected.
Meaning you can't debug a macro that gets defined at the end of the script if you don't understand how the mechanism works.
This creates a wall between the end-user-programmer and the code-base-developer.
That is an understatement. Your project is so large and interconnected, it is very hard to digest a small piece. I imagine there are ideas embedded in your code base that I would appreciate, but they are too difficult to find. It's even worse trying to find solutions to any problems that may be within.

I'm out of ideas, do you have a suggestion on how to do this :oops:

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: ☺?♥♠a♀???☻?☻ for weirdness ♠☺??↨??$error = 7 niet vind

#23 Post by dbenham » 23 Jul 2011 20:53

Sorry Ed, I can't think of anything. The only thing I can suggest is to somehow isolate the problem into a smallish, self contained set of code. But I realize with your project that is very difficult. Unfortunately, you are probably the only one with a reasonable hope of doing it since you understand your code.


Now I have to get something off my chest.

I HATE THIS XP FOR /F BUG :!: :twisted:

Ahhhh...

... That didn't really help :(


Up until now, my macro code hasn't been affected by the XP bug because I always use FOR /F ... IN ("args"). I may have token delimiters within the IN clause, (mainly spaces), but they are quoted so there is no harm done. I've been able to get away with this because I always pass string values by reference and I haven't supported /options.

Now I want to address both shortcomings. I have a perfectly good ParseArgs macro for parsing an argument list that can contain a variable number of /options as well as string literals that have problematic characters encoded. The ParseArgs is used internally by other macros, and it requires that I change the way I call macros in general.
  • Options always come first, with each option preceded by /.
  • The // option signals the end of options just in case the next argument is a string literal that begins with /
  • Any argument (including options) can be enclosed by double quotes like "arg1"
  • Complex arguments containing special characters or token delimiters must be enclosed in double quotes

A handful of special characters must be encoded as follows:

Code: Select all

" -> ""
! -> @e  (e for exclamation)
@ -> @a  (a for at)
% -> @p  (p for percent- not always required, but never hurts)
^ -> @c  (c for caret - not always required, but never hurts)
* -> @s  (s for star)
? -> @q  (q for question - can be done behind the scene)

Suppose I want to pass the following 2 arguments to a macro called MyMacro:
Arg1 = He shouted, "Hello world!"
Arg2 = The world didn't respond.

I also want to pass the following option - but the number of options can vary from call to call:
option = /X

My code would look like this:

Code: Select all

%macro_Call% (' /X "He shouted, ""Hello world@e""" "The world didn't respond" ') %macro.MyMacro%

First %macro_Call% passes the entire argument list as one big string using "usebackq eol=<LF> delims=". Then inside %macro.MyMacro% I include !macro.ParseArgs! which uses a simple FOR loop to break apart the string into 1 option and 2 arguments which are stored in an option and argument array. Each argument is decoded to get the desired value and then MyMacro can go about it's business.

It works great...
... on Vista.

But this infernal XP bug chokes on the naked unquoted/unescaped space between the options and arguments during the initial call. Did I say I hate this bug yet?


I'm convinced that in order for macros to be reliable on XP, we must never use FOR /F with an unescaped/unquoted token delimiter in the IN clause. So I need to modify the design. I have two competing ideas on how to proceed.

First, my ground rules:

- I want the macros to work on XP
- I want to be able to call all my macros in the exact same manner.
- Not all macros need the complex argument parsing and decoding, so I need a small compact argument parser to go along with the complicated one. But the initial macro call must be identical no matter which argument parser is used internally.
- I also need a clean way to call a macro via a function, and the function argument list should look as close to "normal" as possible.

Both options define call_Macro the same way - I use "eol=<LF> delims=" (my ForEntireLine macro), and I use %%. as the FOR argument.

Both options call the macro via a function (small batch file) the same way:

Code: Select all

call callMacro MyMacro /X "He shouted, ""Hello world@e""" "The world didn't respond"

The callMacro function uses the following macros to efficiently process the arguments and call the macro:

Code: Select all

%macro_BeginCall% (%*) %macro.EndCall%
macro_BeginCall uses a simple FOR loop to loop through each argument. The inner workings of macro.EndCall changes depending on the option I choose, but it's job is to transform the argument list into the correct macro_Call form.


Option 1) The design is identical to my existing one, except I substitute ' for ", and any place where I want ' in my argument I encode it as @`.

So here is what the new call looks like:

Code: Select all

%macro_Call% (" /X 'He shouted, ''Hello world@e''' 'The world didn@`t respond' ") %macro.MyMacro%

Everything works as before, but now macro.ParseArgs must convert ' into " and @` into ' before proceeding.

For simple macros that don't need the complex parser I use this simple parser:

Code: Select all

set macro_ParseArgs=for /f "eol= tokens=1-26 delims= " %%a in ("^!%%.^!") do


Option 2) Instead of changing the quote character, I change the argument delimiter from space into something else that won't interfere with other operations, yet is also readily available on the keyboard. I think I will allow the delimiter to be defined at the very start of the library, so people could change it to suit their personal preference. For this discussion I will use the pipe character as a delimiter. Now complex arguments no longer have to be enclosed in double quotes, but internal quotes still need to be doubled.

So arguments are delimited by |, and | within arguments is represented as @d (d for delimiter)

Here is the new call:

Code: Select all

%macro_Call% ("/X|He shouted, ""Hello world@e""|The world didn't respond") %macro.MyMacro%

Now macro.ParseArgs must convert | into <quote><space><quote> (" "), convert @d into |, and add " to the beginning of the 1st argument and " to the end of the last argument

For simple macros that don't need the complex parser I use this simple parser:

Code: Select all

set macro_ParseArgs=for /f "eol=| tokens=1-26 delims=|" %%a in ("^!%%.^!") do



So that's it. I'm having a hard time deciding which encoding I like better (or perhaps which option I dislike the least).

What do you think Ed? I think you could do something along these lines, transformed into your distinct style I'm sure. But it should avoid the XP FOR bug.

Do you have a preference for either syntax? I could use some opinions to help tip the balance in my mind.

Dave Benham

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: ☺?♥♠a♀???☻?☻ for weirdness ♠☺??↨??$error = 7 niet vind

#24 Post by Ed Dyreen » 23 Jul 2011 21:38

'
Do you have a preference for either syntax?
I'm still figuring this out myself aswell...

I see many patterns in your explanation that we have in similar and yes I think we can work around the for ' bug.
For the moment I am working on other things, but when I come up with something I'll let you know. :)
My PM is acting weird and I need to do an unattended as soon as possible.
I have a hard time implementing everything I've learned here.
You guys wiped the floor with me, showing me every corner of the room. :shock:
The result is that I completely broke, bugged and paralized my unattended.
I am not changing anything for the moment I am fixing bugs and implementing the methods.
After I reinstall my OS, I will be at peace and will be able to program in a more iterative way...
You should know that although the for ' bug is ugly, it does not cause my script to crash.
So I am ignoring it for now...

There is one more thing. when I run my script many times in VM, letting it define many variables.
After a while the script starts running slowly. Some sort of memory leak ?

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: ☺?♥♠a♀???☻?☻ for weirdness ♠☺??↨??$error = 7 niet vind

#25 Post by dbenham » 23 Jul 2011 22:50

I think I am leaning toward option 1, only because it is marginally easier to implement given my current code base.

I also just realized that the Option 1 implementation can also support the call like so:

Code: Select all

%macro_Call% (" /X 'He shouted, ""Hello world@e""' 'The world didn@`t respond' ") %macro.MyMacro%

Double quotes within an argument can be encoded as two double quotes ("") or two single quotes ('') and still get the same result.


Dave Benham

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: ☺?♥♠a♀???☻?☻ for weirdness ♠☺??↨??$error = 7 niet vind

#26 Post by Ed Dyreen » 15 Aug 2011 14:36

'

Code: Select all

set macro_ParseArgs=for /f "eol=| tokens=1-26 delims=|" %%a in ("^!%%.^!") do
I don't understand that last piece of code
%%a in ("^!%%.^!")
"!%.!"
What is %. ???! :shock:

1) In your bug workaround, why enclose the IN() clause in single quotes? Your @forU simple FOR loop does not use the single quotes, and then you strip them off later anyway.
You are right that @forU doesn't need them, I could leave it out I guess :mrgreen:
"?=^^^!?:~1,-1^^^!" is required to get rid of the single quotes ! from '$Debug, "This Works"' to $Debug, "This Works".

Code: Select all

set "@Udelim=do set "?=^^^!?^^^!¦%%^^^!" ) &set "?=^^^!?:*¦=^^^!" &set "?=^^^!?:~1,-1^^^!" &for /f "tokens=1-26 delims=¦" %%a in ( "^^^!?^^^!" ) do"
::
%@forU% ( '$Debug, "This Works"' ) %@Udelim% echo. a=%%a_ &echo. b=%%b_

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: ☺?♥♠a♀???☻?☻ for weirdness ♠☺??↨??$error = 7 niet vind

#27 Post by dbenham » 15 Aug 2011 15:19

I don't have access to my code base at the moment, but I think that is a mistake. :lol:
%%a in ("^!%%.^!") should simply be %%a in ("%%.")

%%. is the FOR variable output from my %macro_Call% simple macro. It should contain the entire parameter list as one token.

One other thing that is definitely wrong in my prior post - The %macro_BeginCall%, %macro.EndCall% idea didn't work out well. I gave up trying to use macros and put the code directly in the callMacro function.

I ended up going forward with Option 1.

It's been nearly two weeks since I looked at my code and my memory is a bit hazy. But I think one of my remaining issues concerns my practice of allowing arithemetic expressions for numeric parameters. Because some of the operators are also special characters, it is causing complications - especially in my callMacro function.

At one point I grew frustrated and toyed with the idea of abandoning XP. But I managed a minor breakthrough and still have not given up hope :)

Dave Benham

Acy Forsythe
Posts: 126
Joined: 10 Jun 2011 10:30

Re: ☺?♥♠a♀???☻?☻ for weirdness ♠☺??↨??$error = 7 niet vind

#28 Post by Acy Forsythe » 15 Aug 2011 15:38

I've run into this now too :(

But all my lines are quoted so I REALLY should not be running into it. It's intermittent too which is scary. Sometimes it happens when I build my HTML header, sometimes the footer, sometimes both and sometimes neither. I only found it because I was testing out the macro-ization of the rest of the script (I left the HTML generation parts alone).

I posted the new section of code here:
viewtopic.php?f=3&t=2050&p=9627#p9627

I'm thinking that the beginning unbalanced " character is skewing the parser... At first I thought it was the extra quotes in the first line, but then my footer code generated the same error and it doesn't have an extra set of quotes in any of the lines.

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: ☺?♥♠a♀???☻?☻ for weirdness ♠☺??↨??$error = 7 niet vind

#29 Post by dbenham » 15 Aug 2011 15:59

Acy Forsythe wrote:But all my lines are quoted so I REALLY should not be running into it. It's intermittent too which is scary.
Ahhh- but you do have unquoted/unescaped token delimiters :!: :wink:

I'll post the answer on your referenced topic.

Dave Benham

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: ☺?♥♠a♀???☻?☻ for weirdness ♠☺??↨??$error = 7 niet vind

#30 Post by Ed Dyreen » 15 Aug 2011 17:40

'
My @ForU macro avoids the problem but,
it doesn't process special quoted characters are stripped !

So I created another method that keeps special quoted characters.
This inevitably reintroduces the the FOR /F bug.
What I did is suppressing the bug and hoping for the best, wish me luck

Code: Select all

set @ForL=2^>nul ( for /f ^^^"usebackq^^ eol^^=^^^%$LF%%$LF%^%$LF%%$LF%^^ delims^^=^^^" %%^! in
set @Ldelim= do set "$token=%%~!" ) ^&for /f "tokens=*" %%^! in ( "!$token!" ) do

echo.
setlocal enableextensions enabledelayedexpansion
set /a $ = 0
:loopers
set /a $ += 1
%@ForL% ( '$var, 0, 999, "r?Enum=This Works"' ) %@Ldelim% echo.$token=%%~!
if %$% lss 10 goto :loopers
endlocal

%@endoftest%
The FOR /F bogus error is send to the nul device, I'm hoping this will prevent the bogus code from being executed.
I am settling with this for now :)

Code: Select all

$token=$var 0 999 "r?Enum=This Works"
$token=$var 0 999 "r?Enum=This Works"
$token=$var 0 999 "r?Enum=This Works"
$token=$var 0 999 "r?Enum=This Works"
$token=$var 0 999 "r?Enum=This Works"
$token=$var 0 999 "r?Enum=This Works"
$token=$var 0 999 "r?Enum=This Works"
$token=$var 0 999 "r?Enum=This Works"
$token=$var 0 999 "r?Enum=This Works"
$token=$var 0 999 "r?Enum=This Works"

 endoftest Druk op een toets om door te gaan. . .
Be aware the problem isn't solved, it's gone undercover.
I suggest avoiding the FOR /F bug or using a coding sequence as ben demonstrates to be on the safe side.

Post Reply