Nested FOR loop prevents parent from complete

Microsoft Windows xp professional editio...
September 26, 2009 at 11:57:30
Specs: Windows XP
Hi All,

I have written a batch file that parses an *.ini file, searches for a specific parameter and then replaces its value. I am using a nested FOR loop (see code below) for that purpose.

Code Description:
The parent FOR loop runs on each line of the file. and replicates it in a new file, as long as the desired parameter is not found. When the desired parameter is found, the child FOR loop separates the line into substrings delimited by spaces, replaces the desired parameters and then appends the line to the new file.

The problem
As soon as the nested loop ends, the line with the new paramters is correctly appended, but then the parent loop breaks!

Anyone has an idea on what could possibly went wrong?


:PARSER
SET Result=

REM**********Parent For Loop**********
FOR /F "tokens=1* delims=" %%i in (!SWKEEPERPATH!\swkeeper.ini.bak) do (
  SET line=%%i
  SET lineToParse=%%i
  ECHO !line! | FINDSTR "Dsun.net.client.defaultConnectTimeout">NUL
  IF NOT ERRORLEVEL 1 (
    :SEARCHINLINE

REM**********Child FOR Loop**********
FOR /F "tokens=1* delims= " %%a IN ("!line!") DO (
      ECHO %%a | FINDSTR "Dsun.net.client.defaultConnectTimeout">NUL  
      IF NOT ERRORLEVEL 1 (
        SET Result=!Result! -Dsun.net.client.defaultConnectTimeout=!NewTimeoutMiliSec!
      ) ELSE (
        ECHO %%a | FINDSTR "Dsun.net.client.defaultReadTimeout">NUL  
        IF NOT ERRORLEVEL 1 (
          SET Result=!Result! -Dsun.net.client.defaultReadTimeout=!NewTimeoutMiliSec!
        ) ELSE (
          IF "!Result!" NEQ "" (
            SET Result=!Result! %%a
          ) ELSE (
            SET Result=%%a
          )
        )
      )
      IF "%%b" NEQ "" (
        SET line=%%b
        GOTO :SEARCHINLINE
      ) ELSE (
        ECHO Setting Result
        ECHO !Result!>>!SWKEEPERPATH!\swkeeper.ini
      )
    )
  ) ELSE (

REM**********The part below stops executing**********
REM**********right after the child for loop runs**********
REM**********It did run as long as the condition for the**********
REM**********child loop wasn't met**********

ECHO !lineToParse!>>!SWKEEPERPATH!\swkeeper.ini
  )
)


See More: Nested FOR loop prevents parent from complete

Report •


#1
September 26, 2009 at 13:12:12
It is not allowed to code GOTO statements that jump to labels defined inside a For loop.; so the GOTO :SEARCHINLINE breaks the correct instruction flow of the parent loop.

Inside For loops you must strictly conform to the rules of structured progranning coding CALL to local subroutines (CALL :LABEL parameters) to workaround this issue.


Report •

#2
September 27, 2009 at 00:56:04
Hi IVO,
Thanks for your input. I tried to replace GOTO with CALL, but the output remained the same. So I pulled the nested loop outside the parent and created an external subroutine that I call from the parent loop. It actually seems to do the trick, but it gave me another problem.

The parameter that I am sending to the subroutine (a full line in the file):

args=-server -Xrs -Xms640m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=128m -Dsun.net.client.defaultConnectTimeout=300000 -Dsun.net.client.defaultReadTimeout=300000 -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 "-Djava.endorsed.dirs=C:\jboss-4.0.5\lib\endorsed" -classpath "C:\Program Files\Java\jdk1.6.0_02\lib\tools.jar" -classpath "C:\jboss-4.0.5\bin\run.jar" org.jboss.Main -c

So what happens is that when I call the subroutine with this string as a parameter the subroutine receives the string up to the first double quotes followed by an equal sign:

CALL :SEARCHINLINE "!line!"
...............
..............
:SEARCHLINE
ECHO %1

Output:
"args=-server -Xrs -Xms640m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=128m -Dsun.net.client.defaultConnectTimeout=300000 -Dsun.net.client.defaultReadTimeout=300000 -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 "-Djava.endorsed.dirs


The question now is how can I make it ignore any special characters inside the string?

Any Ideas?

Thanks in advance!


Report •

#3
September 27, 2009 at 03:19:30
[1] Didn't we hammer out this substring change a couple days ago?

[2] If IVO can't fix it, you're in real trouble.


=====================================
Helping others achieve escape felicity

M2


Report •

Related Solutions

#4
September 27, 2009 at 05:24:55
The question now is how can I make it ignore any special characters inside the string?
You can't. Thus the joys of batch scripting.

EDIT: VVVV Timing is everything!


Report •

#5
September 27, 2009 at 05:32:25
LOL

R2 strikes again


=====================================
Helping others achieve escape felicity

M2


Report •

#6
September 27, 2009 at 06:36:47
Razor is right as usual, but in the case we are talking about you have just to code:

CALL :SEARCHINLINE !line!
...............
..............
:SEARCHLINE
  ECHO %*

where %* returns the whole command tail as is.


Report •

#7
September 27, 2009 at 07:37:12
Why even bother passing a variable as a parameter unless you want to use modifiers or for it to be split up on the standard delims? The variable will be valid in the subroutine anyway.

Maybe I'm just missing something or stating the obvious....


Batch Variable how to


Report •

#8
September 28, 2009 at 01:05:13
Hi Mechanix - Yes, this is part of the same process. Every time I get over an obstacle, a new one appears (yes, there must be a Murphy law for that). But I am getting very close to the final solution.

Razor, you scared me! LOL

IVO - You rock dude!

There is only one thing left - Using %*, the whole line is passed on to the subroutine with double quotes at the begining and at the end of the line:

"args=-server -Xrs -Xms640m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=128m -Dsun.net.client.defaultConnectTimeout=300000 -Dsun.net.client.defaultReadTimeout=300000 -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 "-Djava.endorsed.dirs=C:\jboss-4.0.5\lib\endorsed" -classpath "C:\Program Files\Java\jdk1.6.0_02\lib\tools.jar" -classpath "C:\jboss-4.0.5\bin\run.jar" org.jboss.Main -c"

Do I need to code a routine to get rid of them? Is there some kind of way I can pass the string without them?

It can be painful to start writing a routine for that, as there are also double quotes within the string, which of course I don't want them removed.

Thank you all for your help!


Report •

#9
September 28, 2009 at 01:38:27
Why to code a routine when one statement suffices?

:SEARCHLINE
  set tail=%*
  set tail=%tail:~1,-1%
  echo %tail%


Report •

#10
September 28, 2009 at 03:09:22
What are you trying to do?


=====================================
Helping others achieve escape felicity

M2


Report •

#11
September 28, 2009 at 09:47:54
AWESOME!

Thanks a lot to everybody and especially to Mechanix and Ivo.

Mechanix, if this helps someone I can post the whole process.

Please let me know.

Thanks again!


Report •

#12
September 28, 2009 at 10:20:58
It won't hurt to post the whole thing and tell what it does.


=====================================
Helping others achieve escape felicity

M2


Report •

#13
September 29, 2009 at 09:23:38
Ok, here we go:
The general purpose is to parse a file, detect a parameter and then replace its value.

This is done by FOR'ing the whole file to separate it in lines and then each line is searched to find the parameter I want to change.

Here's the code:

:PARSER
SET Result=
REM Parse each line on the file
FOR /F "tokens=1* delims=" %%i in (!SWKEEPERPATH!\swkeeper.ini.bak) do (
 SET line=%%i
 REM Check if line includes string Dsun.net.client.defaultConnectTimeout 
 ECHO !line! | FINDSTR "Dsun.net.client.defaultConnectTimeout">NUL
 IF NOT ERRORLEVEL 1 (
  ECHO Sending param !line! to searchline
  CALL :SEARCHINLINE "!line!"
 ) ELSE (
  REM If string was not found, copy line to destination file as is.
  ECHO !line!>>!SWKEEPERPATH!\swkeeper.ini
 )
)
GOTO :END

:SEARCHINLINE
REM Check each substring (separated by spaces) on line 
SET lineToParse=%*
SET lineToParse=!lineToParse:~1,-1!

ECHO.
ECHO Received param !lineToParse!
FOR /F "tokens=1* delims= " %%a IN ("!lineToParse!") DO (
 REM Check each substring 
 ECHO %%a | FINDSTR "Dsun.net.client.defaultConnectTimeout">NUL  
 IF NOT ERRORLEVEL 1 (
  REM If string is found, agregate the value with parameter change
  SET Result=!Result! -Dsun.net.client.defaultConnectTimeout=!NewTimeoutMiliSec!
 ) ELSE (
  ECHO %%a | FINDSTR "Dsun.net.client.defaultReadTimeout">NUL  
  IF NOT ERRORLEVEL 1 (
   SET Result=!Result! -Dsun.net.client.defaultReadTimeout=!NewTimeoutMiliSec!
  ) ELSE (
   REM To avoid creating a space at the begining of the string
   IF "!Result!" NEQ "" (
    SET Result=!Result! %%a
   ) ELSE (
    SET Result=%%a
   )
  )
 )
 REM Loop until last substring
 IF "%%b" NEQ "" (
  SET lineToParse=%%b
  CALL :SEARCHINLINE !lineToParse!
 ) ELSE (
  ECHO Setting Result
  ECHO !Result!>>!SWKEEPERPATH!\swkeeper.ini
 )
)
GOTO :EOF


Report •

#14
September 29, 2009 at 14:06:56
Do you know what would be easier? Any other language. (VBScript):
Const swkeeperPath = "C:\Whatever\swkeeper.ini"
Const newTimeout = 600000

Set fso = CreateObject("Scripting.FileSystemObject")
swkeeper = fso.OpenTextFile(swkeeperPath).ReadAll
With New RegExp
  .Global = True
  .IgnoreCase = True
  .Pattern = "Timeout=\d+"
  fso.OpenTextFile(swkeeperPath, 2).Write .Replace(swkeeper, _
    "Timeout=" & newTimeout)
End With
WScript.Echo "Done"


Report •

#15
October 2, 2009 at 00:25:57
Thanks Razor.

Yes, I have scripted in other languages (especially linux) and batch code is quite less friendly for parsing.

I wanted to complete this process, which I finally did with the valuable help of you people in this forum.

Next time I will definitely look into vbscript.

Thank you all again!


Report •


Ask Question