Function that makes absolute paths from relative ones

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


Description

This function modifies configuration files. It finds relative paths and changes them to be absolute.

How To Use

Push "/" ;what makes a directory delimiter - i.e. backslash "\", or forward slash "/", or "::" 
Push "D:/MyApplication/onCD/Dir2"				;the base directory (where do I stand?) - must have the same delimiters as above
Push "C:\MyApplication\configuration.conf"	;the file that will be modified
Call MakeAbsolutePath

This will result in:

"./swish-e.exe"   => "D:/MyApplication/onCD/Dir2/swish-e.exe"
"../swish-e.exe"  => "D:/MyApplication/onCD/swish-e.exe"
'./swish-e.exe'   => './swish-e.exe'
"../../../index.swish-e" => "D:/index.swish-e"

And in this nonsense:

"../../../../../../../index.swish-e" => "D:/../../../../index.swish-e"

It is up to you to check if the relative address is correct and you should not use this "./../../myfile.exe". The function is not so clever. You can use "." or ".." but not both in one string.

You can use forward as well as backward slashes, colons, semicolons - whatever you want to delimit directories, but it must to be found in your conf files and in the string that you are passing on to the function. If you do not want to replace something, enclose it in single quotation marks '../../swish-e.exe'

The function doesn't modify variables, but needs the three subfunctions that start with rca - do dot remove them.

Example

Push "/" 
Push "$EXEDIR\myplace"	
Push "C:\MyApplication\configuration.conf"	
Call MakeAbsolutePath

The Functions (MakeAbsolutePath + rca*)

Function MakeAbsolutePath
 
Exch $0 ;the file to search in
Exch
Exch $1 ;the manipulated string
Exch 2
Exch $2 ;the directory delimiter
Exch 
Push $3
Push $4
Push $5
Push $6
Push $R1
Push $R2
Push $R3
Push $R4
Push $R5
 
	StrCpy $3 ""
	StrCpy $4 ""
	StrCpy $5 ""
	StrCpy $6 ""
	StrCpy $R1 ""
	StrCpy $R2 ""
	StrCpy $R3 ""
	StrCpy $R4 ""
	StrCpy $R5 ""
 
 
	StrCpy $R3 $1	;the base directory
	StrCpy $5 $2   ;delimiter
 
	ClearErrors
 
 
		#we start to search for ..$5 (../) - from the short to the longest (../../../.....)
		StrCpy $R1 "..$5"
		loop_dir:
 
		Push $0
		Push "$\"$R1"
		Call rcaFileSearch
 
		;get things out of the stack after the rcaFileSearch finished
			Pop $3
			Pop $2
			Pop $4 
	#DetailPrint " function rcaFileSearch found($\"$R1) ? :($3), ($2) occurrences  in ($4) rows";
 
 
 
		StrCmp $3 yes 0 this_check 	
			StrCpy $R2 $R1	;if we found short, we will try to find a longer one
			StrCpy $R1 "$R1..$5"			
			Goto loop_dir
 
		this_check:
			StrCmp $R2 "" single_dir 0
			StrCpy $R1 $R2					;the latest successful string eg.    "../../../"
			Strlen $R2 $R1	;its length
			Strlen $6 $5
			IntOp $6 $6 + 2
			IntOp $R4 $R2 / $6 	;the number of directories in string eg. 6/3=2 
				#DetailPrint "the number of directories in the string that will be cut off ($R4)"
				#here we have the longest string and the number of directories we may cut off from the base dir
 
				Strlen $3 $R3
		Big_loop:				
				StrCpy $1 0
				StrCpy $2 0
 
				ClearErrors
			Small_loop:
 
				IfErrors single_dir
				IntOp $1 $1 - 1 
					StrCmp "$1" "-255" bezpecnostni_pojistka   ;emergency check, decrease the number of found directories and start again
					StrCpy $R5 $R3 1 $1	
					StrCmp $R5 "$5" 0 Small_loop
						IntOp $2 $2 + 1				
						StrCmp $2 $R4 0 Small_loop	;if the number of loops equals to the number of directories
 
							IntOp $6 $3 + $1 			
							StrCpy $R5 $R3 $6
							StrCpy $R5 "$R5$5"
 
							Push "$\"$R1" #text to be replaced , adding \"
							Push "$\"$R5" #replace with 
							Push all #replace all occurrences 
							Push all #replace all occurrences 
							Push $0 #file to replace in 
 
							Call rcaAdvReplaceInFile 
 
							bezpecnostni_pojistka:
								IntOp $R4 $R4 - 1
								StrCpy $R1 $R1 -3
								StrCmp $R4 0 "" Big_loop
 
			single_dir:
		StrCpy $R3 "$R3$5"
		Push "$\".$5" #text to be replaced 
		Push "$\"$R3" #replace with 
		Push all #replace all occurrences 
		Push all #replace all occurrences 
		Push $0 #file to replace in 
	Call rcaAdvReplaceInFile 
 
 
Pop $R5
Pop $R4
Pop $R3
Pop $R2
Pop $R1
Pop $6
Pop $5
Pop $4
Pop $3
Pop $0
Pop $2
Pop $1
 
 
 
FunctionEnd
;------------------- + -----------------------
Function rcaFileSearch 
 
#this function was written by -Stu (Afrow UK) 
#and is accessible from nsis web pages
#thanks 
 
Exch $0 ;search for
Exch
Exch $1 ;input file
Exch
Push $2
Push $3
Push $4
Push $5
Push $6
Push $7
Push $8
Push $9
Push $R0
ClearErrors
 
  FileOpen $2 $1 r
  StrLen $4 $0
  StrCpy $5 0
  StrCpy $7 no
  StrCpy $8 0
  StrCpy $9 0
loop_main:
  FileRead $2 $3
  IfErrors done
 IntOp $R0 $R0 + $9
  StrCpy $9 0
  StrCpy $5 0
filter_top:
 IntOp $5 $5 - 1
  StrCpy $6 $3 $4 $5
  StrCmp $6 "" loop_main
  StrCmp $6 $0 0 filter_top
  StrCpy $3 $3 $5
  StrCpy $5 0
 StrCpy $7 yes
 StrCpy $9 1
 IntOp $8 $8 + 1
Goto filter_top
done:
  FileClose $2
  StrCpy $0 $8
  StrCpy $1 $7
  StrCpy $2 $R0
Pop $R0
Pop $9
Pop $8
Pop $7
Pop $6
Pop $5
Pop $4
Pop $3
;Exch 2
Exch $2 ;output number of lines
Exch 2
Exch
Exch $0 ;output yes/no
Exch
Exch $1 ;output count found
FunctionEnd
;------------------- + -----------------------
Function rcaAdvReplaceInFile
 
#again, written by Afrow UK 2003-05-18
#I think that there is problem when you do not want to replace all occurrences of text
#but this is not my case
 
Exch $0 ;file to replace in
Exch
Exch $1 ;number to replace after
Exch
Exch 2
Exch $2 ;replace and onwards
Exch 2
Exch 3
Exch $3 ;replace with
Exch 3
Exch 4
Exch $4 ;to replace
Exch 4
Push $5 ;minus count
Push $6 ;universal
Push $7 ;end string
Push $8 ;left string
Push $9 ;right string
Push $R0 ;file1
Push $R1 ;file2
Push $R2 ;read
Push $R3 ;universal
Push $R4 ;count (onwards)
Push $R5 ;count (after)
Push $R6 ;temp file name
 
  GetTempFileName $R6
  FileOpen $R1 $0 r ;file to search in
  FileOpen $R0 $R6 w ;temp file
   StrLen $R3 $4
   StrCpy $R4 -1
   StrCpy $R5 -1
 
loop_read:
 ClearErrors
 FileRead $R1 $R2 ;read line
 IfErrors exit
 
   StrCpy $5 0
   StrCpy $7 $R2
 
loop_filter:
   IntOp $5 $5 - 1
   StrCpy $6 $7 $R3 $5 ;search
   StrCmp $6 "" file_write1			;here was "file_write2"
   StrCmp $6 $4 0 loop_filter
 
 StrCpy $8 $7 $5 ;left part		
 IntOp $6 $5 + $R3
 StrCpy $9 $7 "" $6 ;right part
 
   StrLen $6 $7
 
 StrCpy $7 $8$3$9 ;re-join
 
 
 
;	DetailPrint "-$6 $5 $7"
   StrCmp -$6 $5 0 loop_filter
 
IntOp $R4 $R4 + 1
StrCmp $2 all file_write1
StrCmp $R4 $2 0 file_write2
IntOp $R4 $R4 - 1
 
IntOp $R5 $R5 + 1
StrCmp $1 all file_write1
StrCmp $R5 $1 0 file_write1
IntOp $R5 $R5 - 1
Goto file_write2
 
file_write1:
FileWrite $R0 $7 ;write modified line
Goto loop_read
 
file_write2:
 FileWrite $R0 $R2 ;write unmodified line
Goto loop_read
 
exit:
  FileClose $R0
  FileClose $R1
 
  SetDetailsPrint none
  Delete $0
  Rename $R6 $0
  Delete $R6
  SetDetailsPrint both
 
Pop $R6
Pop $R5
Pop $R4
Pop $R3
Pop $R2
Pop $R1
Pop $R0
Pop $9
Pop $8
Pop $7
Pop $6
Pop $5
Pop $0
Pop $1
Pop $2
Pop $3
Pop $4
FunctionEnd
;====================================================
 
 
Function rcaChangeBackslash
	Exch $R1 ;string to search in
	Push $R2
	Push $R3
	Push $1
		StrCpy $R2 ""
		StrCpy $R3 ""
 
	ClearErrors
   StrCpy "$1" 0   							#counter
;	GetFullPathName /SHORT $R1 $9
	Znovu:
		StrCpy "$R2" "$R1" 1 "$1"
		StrCmp "$R2" "" Konec "" 
		StrCmp "$R2" "\" "" +2
		StrCpy "$R2" "/"
		StrCpy "$R3" "$R3$R2"
 
		IntOp "$1" "$1" + 1
		Goto Znovu
	Konec:
	StrCpy $R1 $R3
	Pop $1
	Pop $R3
	Pop $R2
	Exch $R1
 
 
 
FunctionEnd

(rca 2004-04)
Good luck.