Archive: How Do You Use TrimNewLine to Remove All $\r$\n at The End of a File?


How Do You Use TrimNewLine to Remove All $\r$\n at The End of a File?
I am having a problem with this function. I really do not know how to apply it, yet I think I need it. Basically I am trying to open a file which might look like the following.


78. blah
79. last line
80.
81.
82.
I need to delete lines 80, 81 and 82. In the end this file should look like this
78. blah
79. last line
I am really not understanding where to place this function or how to call it. I am using file open for some other actions so do I place this call after fileopen? I've tried many things and I feel am getting no where. Can someone please help point out to me how to do what it is I am trying to do?

Also I searched the forums and help files but no real good examples exist on how exactly this function could be used in a real world scenario. Also, I cannot pinpoint the last word found in the file because it could be anything. Also, I am not trying to replace a word or character but am trying to simply clean up the end of the file.

Can someone help me out. Thank you for understanding and for your time.

I don't wish to start a new thread but thought it would be nice if someone with the skills created a file cleanup function. i.e.

1. Remove consecutive empty lines until only one line remains.
2. Remove trailing spaces from a file line for line.
3. etc

Just an idea. Just thinking. Thanks to the wo/man who can get this done if somoene decides to take this on.

Thanks again!


Name 'Output'
OutFile 'Output.exe'

!include "TextFunc.nsh"
!insertmacro LineFind
!insertmacro LineRead
!insertmacro TrimNewLines

!define Input "C:\Input.txt"
!define Output "C:\Output.txt"

Section
StrCpy $0 -1

loop:
${LineRead} "${Input}" "$0" $1
${TrimNewLines} "$1" $1
StrCmp $1 "" 0 +3
IntOp $0 $0 - 1
goto loop

${LineFind} "${Input}" "${Output}" "$0:-1" "CallbackLineFind"
SectionEnd

Function CallbackLineFind
StrCmp $R0 FirstLine SkipWrite
StrCpy $R0 FirstLine
${TrimNewLines} "$R9" $R9
goto end

SkipWrite:
StrCpy $0 SkipWrite

end:
Push $0
FunctionEnd

Script used header

Thanks Instructor,

Very cool. I worked with it and managed to copy contents from one file into another and even into itself with trimmed lines. Thank you. Can this function be smart enough to scan a file from top to bottom and remove all consecutive empty lines (not just empty lines with something above or beneath it)?

i.e.

79. txt
80.
81.
82. nsi
83.
84.
85.
86. wow a lot of empty space
87.
88.
85. nsh



to this

79. txt
80.
81. nsi
82.
83. wow a lot of empty space
84.
85. nsh


Basically just removing an empty line if an empty line exist beneath or above it? I haven't got the logic to do it myself. The farthest I got was replacing all lines or removing all $\r$\n to the point where everything ended up smashed together...

Thanks a million for the function Instructor.

Name 'Output'
OutFile 'Output.exe'

!include "TextFunc.nsh"
!insertmacro LineFind
!insertmacro TrimNewLines

!define Input "C:\Input.txt"
!define Output "C:\Output.txt"

Section
${LineFind} "${Input}" "${Output}" "1:-1" "CallbackLineFind"
SectionEnd

Function CallbackLineFind
${TrimNewLines} "$R9" $1
StrCmp $1 "" +3
StrCpy $R0 ""
goto end

StrCmp $R0 FoundEmpty SkipWrite
StrCpy $R0 FoundEmpty
goto end

SkipWrite:
StrCpy $0 SkipWrite

end:
Push $0
FunctionEnd

Script used header

You're the man... I've been up all night trying to figure this out and my skills with NSIS is still young. I have just one last question. I know how to work with functions a bit but can you help me figure out how to turn your work into some very simple insertmacros?

i.e.

!insertmacro CleanLines $EXEDIR.test.txt ;clean all lines
!insertmacro CleanEOF $EXEDIR.test.txt ;clean last line
OR
!insertmacro CleanLines CleanEOF $EXEDIR.test.txt ;clean all lines including the end.


The reason I ask is because it seems I would have to duplicate the code for every file I need cleaned. This wouldn't be a problem if you gave up now as you've put me way ahead of myself (thank you). Also, once this is done and tightened up please share it with the world on the archives. Call it "File Cleaner Version 1.0".

1.0 Because I am certain others will need deeper cleaning :)

Thanks a million again Instructor, your work is priceless!

Name 'Output'
OutFile 'Output.exe'

!include "TextFunc.nsh"
!insertmacro LineFind
!insertmacro LineRead
!insertmacro TrimNewLines

Function CleanLines
Exch $1
Exch
Exch $0
Exch
Push $R0

${LineFind} "$0" "$1" "1:-1" "CallbackCleanLines"

Pop $R0
Pop $1
Pop $0
FunctionEnd

Function CallbackCleanLines
${TrimNewLines} "$R9" $1
StrCmp $1 "" +3
StrCpy $R0 ""
goto end

StrCmp $R0 FoundEmpty SkipWrite
StrCpy $R0 FoundEmpty
goto end

SkipWrite:
StrCpy $0 SkipWrite

end:
Push $0
FunctionEnd


Function CleanEOF
Exch $1
Exch
Exch $0
Exch
Push $2
Push $3
Push $R0

StrCpy $2 -1

loop:
${LineRead} "$0" "$2" $3
${TrimNewLines} "$3" $3
StrCmp $3 "" 0 +3
IntOp $2 $2 - 1
goto loop

${LineFind} "$0" "$1" "$2:-1" "CallbackCleanEOF"

Pop $R0
Pop $3
Pop $2
Pop $1
Pop $0
FunctionEnd

Function CallbackCleanEOF
StrCmp $R0 FirstLine SkipWrite
StrCpy $R0 FirstLine
${TrimNewLines} "$R9" $R9
goto end

SkipWrite:
StrCpy $0 SkipWrite

end:
Push $0
FunctionEnd



!macro CleanLines "_INPUT" "_OUTPUT"
Push "${_INPUT}"
Push "${_OUTPUT}"
Call CleanLines
!macroEnd

!macro CleanEOF "_INPUT" "_OUTPUT"
Push "${_INPUT}"
Push "${_OUTPUT}"
Call CleanEOF
!macroEnd

!macro CleanLines+CleanEOF "_INPUT" "_OUTPUT"
Push "${_INPUT}"
Push "${_OUTPUT}"
Call CleanLines

Push "${_OUTPUT}"
Push "${_OUTPUT}"
Call CleanEOF
!macroEnd


Section
!insertmacro CleanLines+CleanEOF "C:\Input1.txt" "C:\Output1.txt"
!insertmacro CleanLines+CleanEOF "C:\Input2.txt" "C:\Output2.txt"
SectionEnd


Script used header

If you want you can share it.

Wow, Amazing!

This is a must share script. Super fantastic and fabulous work. Was working on my version by modifying your scripts a little but I kept getting stuck on an evil loop :(

This is awesome, if you wish I will put it in the archives on your behalf but I'd suggest you best put it under your belt ;) It works without hiccups right out of the box. Awesome!

Thanks for your help Instructor, I know others will find it useful! Keep up the great work!

Best Regards!


I'm glad to help you.

For empty files support:

        ...
${LineRead} "$0" "$2" $3
IfErrors end
...

...
end:
Pop $R0
...


To remove spaces and "tab" at the end of lines:
Function CallbackCleanLines
${TrimNewLines} "$R9" $R9
StrCpy $1 $R9 1 -1
StrCmp $1 " " +2
StrCmp $1 " " 0 +3
StrCpy $R9 $R9 -1
goto -4
StrCpy $R9 "$R9$\r$\n"

StrCmp $R9 "$\r$\n" +3
StrCpy $R0 ""
goto end

StrCmp $R0 FoundEmpty SkipWrite
...

So replace this

Function CleanEOF
Exch $1
Exch
Exch $0
Exch
Push $2
Push $3
Push $R0

StrCpy $2 -1

loop:
${LineRead} "$0" "$2" $3

${TrimNewLines} "$3" $3
StrCmp $3 "" 0 +3
IntOp $2 $2 - 1
goto loop

${LineFind} "$0" "$1" "$2:-1" "CallbackCleanEOF"

Pop $R0
Pop $3
Pop $2
Pop $1
Pop $0
FunctionEnd
With the following and this enables empty file support?
Function CleanEOF
Exch $1
Exch
Exch $0
Exch
Push $2
Push $3
Push $R0

StrCpy $2 -1

loop:
${LineRead} "$0" "$2" $3
IfErrors end
${TrimNewLines} "$3" $3
StrCmp $3 "" 0 +3
IntOp $2 $2 - 1
goto loop

${LineFind} "$0" "$1" "$2:-1" "CallbackCleanEOF"
end:
Pop $R0
Pop $3
Pop $2
Pop $1
Pop $0
FunctionEnd
What exactly does this mean? In case I try to clean up an empty file, the error flag is set and the actions are skipped?

To enable tab and trailing space support I replace this
Function CallbackCleanLines
${TrimNewLines} "$R9" $1
StrCmp $1 "" +3
StrCpy $R0 ""
goto end

StrCmp $R0 FoundEmpty SkipWrite
StrCpy $R0 FoundEmpty
goto end

SkipWrite:
StrCpy $0 SkipWrite

end:
Push $0
FunctionEnd
With this?
Function CallbackCleanLines
${TrimNewLines} "$R9" $R9
StrCpy $1 $R9 1 -1
StrCmp $1 " " +2
StrCmp $1 " " 0 +3
StrCpy $R9 $R9 -1
goto -4
StrCpy $R9 "$R9$\r$\n"

StrCmp $R9 "$\r$\n" +3
StrCpy $R0 ""
goto end


StrCmp $R0 FoundEmpty SkipWrite

${TrimNewLines} "$R9" $1
StrCmp $1 "" +3
StrCpy $R0 ""
goto end

StrCmp $R0 FoundEmpty SkipWrite
StrCpy $R0 FoundEmpty
goto end

SkipWrite:
StrCpy $0 SkipWrite

end:
Push $0
FunctionEnd
I think I might have messed up this function on this paste. Does it seem correct? I will give these functions a stab in a minute. Just confirming in case I start to steer off early.

FileCleanUp time :) Yes!

In case I try to clean up an empty file, the error flag is set and the actions are skipped?
Yes.


Name 'Output'
OutFile 'Output.exe'

!include "TextFunc.nsh"
!insertmacro LineFind
!insertmacro LineRead
!insertmacro TrimNewLines

Function CleanLines
Exch $1
Exch
Exch $0
Exch
Push $R0

${LineFind} "$0" "$1" "1:-1" "CallbackCleanLines"

Pop $R0
Pop $1
Pop $0
FunctionEnd

Function CallbackCleanLines
${TrimNewLines} "$R9" $R9
StrCpy $1 $R9 1 -1
StrCmp $1 " " +2
StrCmp $1 " " 0 +3
StrCpy $R9 $R9 -1
goto -4
StrCpy $R9 "$R9$\r$\n"

StrCmp $R9 "$\r$\n" +3
StrCpy $R0 ""
goto end

StrCmp $R0 FoundEmpty SkipWrite
StrCpy $R0 FoundEmpty
goto end

SkipWrite:
StrCpy $0 SkipWrite

end:
Push $0
FunctionEnd


Function CleanEOF
Exch $1
Exch
Exch $0
Exch
Push $2
Push $3
Push $R0

StrCpy $2 -1

loop:
${LineRead} "$0" "$2" $3
IfErrors end

${TrimNewLines} "$3" $3
StrCmp $3 "" 0 +3
IntOp $2 $2 - 1
goto loop

${LineFind} "$0" "$1" "$2:-1" "CallbackCleanEOF"

end:
Pop $R0
Pop $3
Pop $2
Pop $1
Pop $0
FunctionEnd

Function CallbackCleanEOF
StrCmp $R0 FirstLine SkipWrite
StrCpy $R0 FirstLine
${TrimNewLines} "$R9" $R9
goto end

SkipWrite:
StrCpy $0 SkipWrite

end:
Push $0
FunctionEnd



!macro CleanLines "_INPUT" "_OUTPUT"
Push "${_INPUT}"
Push "${_OUTPUT}"
Call CleanLines
!macroEnd

!macro CleanEOF "_INPUT" "_OUTPUT"
Push "${_INPUT}"
Push "${_OUTPUT}"
Call CleanEOF
!macroEnd

!macro CleanLines+CleanEOF "_INPUT" "_OUTPUT"
Push "${_INPUT}"
Push "${_OUTPUT}"
Call CleanLines

Push "${_OUTPUT}"
Push "${_OUTPUT}"
Call CleanEOF
!macroEnd


Section
!insertmacro CleanLines+CleanEOF "C:\Input1.txt" "C:\Output1.txt"
!insertmacro CleanLines+CleanEOF "C:\Input2.txt" "C:\Output2.txt"
SectionEnd

Powerful. Thank you for sharing this with me and thank you so much for your time and effort in creating a really great file clean up function. The archives thirsty for this one :)

Your work is undoubtedly appreciated and I thank you again!

It works great!:up: :up: :up: :up: :up:


vbgunz, it's not necessary so much thanks :).
I had an idea and wrote new compact code. Now if you use CleanLines function you don't need to use CleanEOF. If you found it interesting... :

Name 'Output'
OutFile 'Output.exe'

!include "TextFunc.nsh"
!insertmacro LineFind
!insertmacro TrimNewLines

Function CleanLines
Exch $1
Exch
Exch $0
Exch
Push $R0

${LineFind} "$0" "$1" "1:-1" "CallbackCleanLines"

Pop $R0
Pop $1
Pop $0
FunctionEnd

Function CallbackCleanLines
${TrimNewLines} "$R9" $R9
StrCpy $1 $R9 1 -1
StrCmp $1 " " +2
StrCmp $1 " " 0 +3
StrCpy $R9 $R9 -1
goto -4
StrCpy $R9 "$R9$\r$\n"

StrCmp $R9 "$\r$\n" +5
StrCmp $R0 FoundEmpty 0 end
FileWrite $R7 "$\r$\n"
StrCpy $R0 ""
goto end

StrCpy $R0 FoundEmpty
StrCpy $0 SkipWrite

end:
Push $0
FunctionEnd


!macro CleanLines "_INPUT" "_OUTPUT"
Push "${_INPUT}"
Push "${_OUTPUT}"
Call CleanLines
!macroEnd


Section
!insertmacro CleanLines "C:\Input1.txt" "C:\Output1.txt"
!insertmacro CleanLines "C:\Input2.txt" "C:\Output2.txt"
SectionEnd

Hello Instructor,

You can never thank someone enough when they do something for you in which you cannot do for youself :) Sorry, its custom for me to extend my thanks and gratitude.

The last piece of code you've shared fails to remove the very last $\r$\n and so one last blank line is left behind. Other than this, it does clean up everything else.

1. consecutive empty lines
2. trailing white spaces on end of lines
3. End of file but leaves one blank line behind
4. Skip empty files

Great work so far in compacting the code although I am sticking with your second to last post. That one is perfect ;)

Thanks again Instructor. I appreciate your time!


The last piece of code you've shared fails to remove the very last $\r$\n
Yes, so was conceived. If you don't need "last $\r$\n" use CleanEOF after.

My apologies Instructor. Thank you for your help. Major thanks will be written in my script ;)