LineFind

From NSIS Wiki
Jump to navigationJump to search
Author: Instructor (talk, contrib)


Page for NSIS 2.07 and below users

You can use the latest version of headers (recommended) or the following function code (put the function code in your script before calling it)

Function Description

____________________________________________________________________________
 
                            LineFind v1.5
____________________________________________________________________________
 
 
Find specified lines in text file and edit or view this lines in callback function.
 
 
Syntax:
${LineFind} "[File1]" "[File2|/NUL]" "[LineNumbers]" "Function"
 
"[File1]"         ; Input text file
                  ;
"[File2|/NUL]"    ; [File2]
                  ;   Output text file
                  ;   If empty then File2=File1
                  ; [/NUL]
                  ;   No output text file (only read File1)
                  ;
"[LineNumbers]"   ; [No|-No|No:No|{No}|{-No}|{No:No}]
                  ;   1:-1     all lines to change (default)
                  ;   2        second line from start
                  ;   -3       third line from end
                  ;   5:9      range of lines from 5 to 9
                  ;   {2}      only second line from start to output
                  ;   {-3}     only third line from end to output
                  ;   {5:9}    only range of lines from 5 to 9 to output
                  ;
"Function"        ; Callback function for specified lines
 
Function "Function"
	; $R9       current line
	; $R8       current line number
	; $R7       current line negative number
	; $R6       current range of lines
	; $R5       handle of a file opened to read
	; $R4       handle of a file opened to write ($R4="" if "/NUL")
 
	; you can use any string functions
	; $R0-$R3  are not used (save data in them).
	; ...
 
	Push $var      ; If $var="StopLineFind"  Then exit from function
	               ; If $var="SkipWrite"     Then skip current line (ignored if "/NUL")
FunctionEnd
 
 
Note:
-Error flag if input file isn't exists
-Error flag if output file path isn't exists
-Ranges must be specified on growth (2 4:5 9:-8 -5:-4 -2:-1)
-Output file will not be updated if no changes made.


Example1 (delete first two symbols):

Section
	${LineFind} "C:\a.log" "C:\a-edited.log" "3:-1" "Example1"
	IfErrors 0 +2
	MessageBox MB_OK "Error"
SectionEnd
 
Function Example1
	${TrimNewLines} '$R9' $R9
	StrCpy $R9 $R9 '' 2
	StrCpy $R9 '$R9$\r$\n'
	;start from 3 line and delete first two symbols
 
	Push $0
FunctionEnd


Example2 (show changed lines):

Section
	${LineFind} "C:\a.log" "a.log" "{5:12 15 -6:-5 -1}" "Example2"
	IfErrors 0 +2
	MessageBox MB_OK "Error"
SectionEnd
 
Function Example2
	${TrimNewLines} '$R9' $R9
	StrCpy $R9 "$R9   ~Changed line ($R8)~$\r$\n"
 
	Push $0
FunctionEnd


Example3 (delete lines):

Section
	${LineFind} "C:\a.log" "\logs\a.log" "2:3 10:-5 -3:-2" "Example3"
	IfErrors 0 +2
	MessageBox MB_OK "Error"
SectionEnd
 
Function Example3
	StrCpy $0 SkipWrite
 
	Push $0
FunctionEnd


Example4 (insert lines):

Section
	${LineFind} "C:\a.log" "" "10" "Example4"
	IfErrors 0 +2
	MessageBox MB_OK "Error"
SectionEnd
 
Function Example4
	FileWrite $R4 "---First Line---$\r$\n"
	FileWrite $R4 "---Second Line ...---$\r$\n"
 
	Push $0
FunctionEnd


Example5 (replace in file with count of changes - "WordFunc.nsh" required):

!include "WordFunc.nsh"
!insertmacro WordReplace
 
Section
	StrCpy $R0 0
	${LineFind} "C:\a.log" "C:\logs\a.log" "1:-1" "Example5"
	IfErrors 0 +2
	MessageBox MB_OK "Error" IDOK +2
	MessageBox MB_OK "Changed lines=$R0"
SectionEnd
 
Function Example5
	StrCpy $1 $R9
 
	${WordReplace} '$R9' ' ' '_' '+*' $R9
 
	StrCmp $1 $R9 +2
	IntOp $R0 $R0 + 1
	;$R0   count of changed lines
 
	Push $0
FunctionEnd


Example6 (line string to cut or delete):

Section
	${LineFind} "\a.log" "C:\logs\a.log" "" "Example6"
	IfErrors 0 +2
	MessageBox MB_OK "Error" IDOK +2
	MessageBox MB_OK "Processed lines=$R1:$R2"
SectionEnd
 
Function Example6
	;(Cut lines from a line to another line (also including that line))
	StrCmp $R0 finish stop
	StrCmp $R0 start finish
	StrCmp $R9 'Start Line$\r$\n' 0 skip
	StrCpy $R0 start
	StrCpy $R1 $R8
	goto code
	finish:
	StrCmp $R9 'Finish Line$\r$\n' 0 code
	StrCpy $R0 finish
	StrCpy $R2 $R8
	goto code
	skip:
	StrCpy $0 SkipWrite
	goto output
	stop:
	StrCpy $0 StopLineFind
	goto output
 
	;;(Delete lines from a line to another line (also including that line))
	; StrCmp $R0 finish code
	; StrCmp $R0 start finish
	; StrCmp $R9 'Start Line$\r$\n' 0 code
	; StrCpy $R0 start
	; StrCpy $R1 $R8
	; goto skip
	; finish:
	; StrCmp $R9 'Finish Line$\r$\n' 0 skip
	; StrCpy $R0 finish
	; StrCpy $R2 $R8
	; skip:
	; StrCpy $0 SkipWrite
	; goto output
 
	code:
	;...
 
	output:
	Push $0
FunctionEnd


Example7 (read lines):

Section
	${LineFind} "C:\a.log" "/NUL" "1:-1" "Example7"
	IfErrors 0 +2
	MessageBox MB_OK "Error"
SectionEnd
 
Function Example7
	MessageBox MB_OKCANCEL '$$R9  "Line"=[$R9]$\n$$R8     "#" =[$R8]' IDOK +2
	StrCpy $0 StopLineFind
 
	Push $0
FunctionEnd

Function Code

Function LineFind
	!define LineFind `!insertmacro LineFindCall`
 
	!macro LineFindCall _INPUT _OUTPUT _RANGE _FUNC
		Push $0
		Push `${_INPUT}`
		Push `${_OUTPUT}`
		Push `${_RANGE}`
		GetFunctionAddress $0 `${_FUNC}`
		Push `$0`
		Call LineFind
		Pop $0
	!macroend
 
	Exch $3
	Exch
	Exch $2
	Exch
	Exch 2
	Exch $1
	Exch 2
	Exch 3
	Exch $0
	Exch 3
	Push $4
	Push $5
	Push $6
	Push $7
	Push $8
	Push $9
	Push $R4
	Push $R5
	Push $R6
	Push $R7
	Push $R8
	Push $R9
	ClearErrors
 
	IfFileExists '$0' 0 error
	StrCmp $1 '/NUL' begin
	StrCpy $8 0
	IntOp $8 $8 - 1
	StrCpy $9 $1 1 $8
	StrCmp $9 \ +2
	StrCmp $9 '' +3 -3
	StrCpy $9 $1 $8
	IfFileExists '$9\*.*' 0 error
 
	begin:
	StrCpy $4 1
	StrCpy $5 -1
	StrCpy $6 0
	StrCpy $7 0
	StrCpy $R4 ''
	StrCpy $R6 ''
	StrCpy $R7 ''
	StrCpy $R8 0
 
	StrCpy $8 $2 1
	StrCmp $8 '{' 0 delspaces
	StrCpy $2 $2 '' 1
	StrCpy $8 $2 1 -1
	StrCmp $8 '}' 0 delspaces
	StrCpy $2 $2 -1
	StrCpy $R6 cut
 
	delspaces:
	StrCpy $8 $2 1
	StrCmp $8 ' ' 0 +3
	StrCpy $2 $2 '' 1
	goto -3
	StrCmp $2$7 '0' file
	StrCpy $4 ''
	StrCpy $5 ''
	StrCmp $2 '' writechk
 
	range:
	StrCpy $8 0
	StrCpy $9 $2 1 $8
	StrCmp $9 '' +5
	StrCmp $9 ' ' +4
	StrCmp $9 ':' +3
	IntOp $8 $8 + 1
	goto -5
	StrCpy $5 $2 $8
	IntOp $5 $5 + 0
	IntOp $8 $8 + 1
	StrCpy $2 $2 '' $8
	StrCmp $4 '' 0 +2
	StrCpy $4 $5
	StrCmp $9 ':' range
 
	IntCmp $4 0 0 +2
	IntCmp $5 -1 goto 0 growthcmp
	StrCmp $R7 '' 0 minus2plus
	StrCpy $R7 0
	FileOpen $8 $0 r
	FileRead $8 $9
	IfErrors +3
	IntOp $R7 $R7 + 1
	Goto -3
	FileClose $8
 
	minus2plus:
	IntCmp $4 0 +5 0 +5
	IntOp $4 $R7 + $4
	IntOp $4 $4 + 1
	IntCmp $4 0 +2 0 +2
	StrCpy $4 0
	IntCmp $5 -1 goto 0 growthcmp
	IntOp $5 $R7 + $5
	IntOp $5 $5 + 1
	growthcmp:
	IntCmp $4 $5 goto goto
	StrCpy $5 $4
	goto:
	goto $7
 
	file:
	StrCmp $1 '/NUL' +4
	GetTempFileName $R4
	Push $R4
	FileOpen $R4 $R4 w
	FileOpen $R5 $0 r
	IfErrors preerror
 
	loop:
	IntOp $R8 $R8 + 1
	FileRead $R5 $R9
	IfErrors handleclose
 
	cmp:
	StrCmp $2$4$5 '' writechk
	IntCmp $4 $R8 call 0 writechk
	StrCmp $5 -1 call
	IntCmp $5 $R8 call 0 call
 
	GetLabelAddress $7 cmp
	goto delspaces
 
	call:
	StrCpy $7 $R9
	Push $0
	Push $1
	Push $2
	Push $3
	Push $4
	Push $5
	Push $6
	Push $7
	Push $R4
	Push $R5
	Push $R6
	Push $R7
	Push $R8
	StrCpy $R6 '$4:$5'
	StrCmp $R7 '' +3
	IntOp $R7 $R8 - $R7
	IntOp $R7 $R7 - 1
	Call $3
	Pop $9
	Pop $R8
	Pop $R7
	Pop $R6
	Pop $R5
	Pop $R4
	Pop $7
	Pop $6
	Pop $5
	Pop $4
	Pop $3
	Pop $2
	Pop $1
	Pop $0
	IfErrors preerror
	StrCmp $9 'StopLineFind' 0 +3
	IntOp $6 $6 + 1
	goto handleclose
	StrCmp $1 '/NUL' loop
	StrCmp $9 'SkipWrite' 0 +3
	IntOp $6 $6 + 1
	goto loop
	StrCmp $7 $R9 write
	IntOp $6 $6 + 1
	goto write
 
	writechk:
	StrCmp $1 '/NUL' loop
	StrCmp $R6 cut 0 write
	IntOp $6 $6 + 1
	goto loop
 
	write:
	FileWrite $R4 $R9
	goto loop
 
	preerror:
	SetErrors
 
	handleclose:
	StrCmp $1 '/NUL' +3
	FileClose $R4
	Pop $R4
	FileClose $R5
	IfErrors error
 
	StrCmp $1 '/NUL' end
	StrCmp $1 '' 0 +2
	StrCpy $1 $0
	StrCmp $6 0 0 rename
	FileOpen $7 $0 r
	FileSeek $7 0 END $8
	FileClose $7
	FileOpen $7 $R4 r
	FileSeek $7 0 END $9
	FileClose $7
	IntCmp $8 $9 0 rename
	Delete $R4
	StrCmp $1 $0 end
	CopyFiles /SILENT $0 $1
	goto end
 
	rename:
	Delete '$EXEDIR\$1'
	Rename $R4 '$EXEDIR\$1'
	IfErrors 0 end
	Delete $1
	Rename $R4 $1
	IfErrors 0 end
 
	error:
	SetErrors
 
	end:
	Pop $R9
	Pop $R8
	Pop $R7
	Pop $R6
	Pop $R5
	Pop $R4
	Pop $9
	Pop $8
	Pop $7
	Pop $6
	Pop $5
	Pop $4
	Pop $3
	Pop $2
	Pop $1
	Pop $0
FunctionEnd