I think the default dir gets a trailing slash.
But what if the user selects a different directory?
Is there a way for the INSTALLDIR to NOT have a trailing slash?
It's not that I want it to not have a trailing slash. I want to know if I can count on it, so that, for example,
[INSTALLDIR]Filter.dll
...will always resolve to a real, valid filesystem path.
Currently I use
[INSTALLDIR]\Filter.dll
and I get a double-slash in there. It's valid and resolves, but I'd like to eliminate the double slash.
thanks.
Windows Instaler directory table entries ( which become properties after costing ) are always formatted by MSI to contain a trailing backslash. Including extra slashes will not harm the resolution.
It is my understanding that Windows Installer will add a backslash to any Directory table entry. Therefore, yes, you can eliminate your slash and not worry about things breaking.
In fact, this has even prompted InstallShield to create a KB article describing how to REMOVE the backslash...
http://kb.flexerasoftware.com/selfservice/viewContent.do?externalID=Q106587
Related
I've many VBA scripts and functions where I read a manually inserted (in Excel cell) local disk paths and I'm still confused about whether to normalize the inserted paths by adding or trimming the trailing backslash.
What do you use as the general standard? with or without the trailing backslash?
My confusion is fueled by the fact that for example ActiveWorkbook.path returns a path without trailing backslash while the CopyFile (FileSystemObject) method for the "Destination" parameter wants the trailing backslash otherwise it considers it as a file instead than a directory (and can give unexpected Permission denied errors)
The general idea is to always end a directory's name with a backslash. This is advised in the URL you mention, but there are quite some other situations as well (check my answer on a regularly occuring xcopy problem).
As mentioned: when you don't put a backslash, the question might arise "Is it a file or a directory?". Putting the backslash solves that question.
In top of that, while programming, regularly you might have following situation:
complete_filename = path + filename
Obviously, if you have forgotten to put the backslash at the end, this might cause problems (e.g. you don't want to create a file, called "C:\Tempoutput.txt" instead of "C:\Temp\output.txt", I presume? :-) )
I have an SSIS package with an ForEach File Enumerate loop (Fully Qualified Name) with an FTP task within in.
The package when executed will go through the files in the subfolders within the following directory
C:\Test\Test2\ABC\
*.txt
And it will post the files to an FTP site.
I have a defined variable called #[User::Filename] within the foreach loop.
But there are folders within the FTP and I want the files to go to based on the Folder they are taken from on the C drive.
C:\Test\Test2\ABC\A\1.txt
C:\Test\Test2\ABC\B\2.txt
C:\Test\Test2\ABC\C\3.txt
File 1.txt should go to the FTP folder Called \FTP\A
File 2.txt should go to the FTP folder Called \FTP\B
File 3.txt should go to the FTP folder Called \FTP\C
My original thought was to make the remote path a variable and piggy back off the the foreach loop variable Fully qualified name.
To do this I created a variable called #[User::FilenameFTP] and inputted the following into the expression
"//FTP//" +
RIGHT(
(LEFT(#[User::Filename], ABS((FINDSTRING(#[User::Filename], "//", 5)))),
ABS((FINDSTRING(#[User::Filename], "//", 5)-1)) - ABS((FINDSTRING(#[User::Filename], "//",4)+1))
)
I thought this formula would give me the filename in the C drive which the file is coming from and I used this as the Remote Path variable within the FTP task. But when I run it the files still go into \FTP\ and not into the subfolders.
I ran a script task on this and the output isnt showing what I want either. What am I doing wrong? Can this not be done this way editing the variable within the foreach loop?
If your drive names are coming in (more or less) as you have them shown, then those should be backslashes ("\\") instead of forward slashes in your expression. Might not be the issue, but I changed them to play around with this.
Using the C folder string, in the expression as written, ABS((FINDSTRING(#[User::Filename], "\\", 5)-1)) and ABS((FINDSTRING(#[User::Filename], "\\",4)+1)) both evaluate to 19, so the expression comes down to RIGHT(<<String>>,0), and, from the documentation, If integer_expression is zero, the function returns a zero-length string.. So you're not appending anything to the end of the FTP base folder name.
Down and Dirty Fix
We could probably mess around with all that LEFT and RIGHT and FINDSTRING, but if you know that the folder name you're after will always be the fifth element in your fully qualified name (which your expression is already dependent on) you can get there faster just using TOKEN, and specifying the fifth element of your slash-delimited string:
"//FTP//" + TOKEN( #[User::Filename],"\\",5) +"//"
Which evaluates to //FTP//C//.
More Sustainable Fix
On the other hand, if you want to future-proof your code a little, in anticipation of the day that you add or eliminate a level of folder hierarchy, I would suggest extracting the last folder name, without regard to how many levels of folder come first.
We can do that using SUBSTRING and some clever REVERSE work, with due credit to KeithL for this answer, that got me rolling.
SUBSTRING takes three arguments. We have our string #[User::Filename], so that's one. The second is the starting position from the left end of the string, and the third is the number of characters to extract.
To get the starting position, we'll find the position of the second to last slash using REVERSE to count characters from the right hand end of the string:
FINDSTRING(REVERSE( #[User::Filename]),"\\",2) (evaluates to 8 here)
So our starting position is the total length of the string, minus the number of characters back to the second to last slash.
LEN( #[User::Filename]) - FINDSTRING(REVERSE( #[User::Filename]),"\\",2) (=17)
We can get the number of characters to pull by subtracting the reversed position of the last slash from the reversed position of the second to last slash, then subtracting one more, since we don't want that trailing slash in our string yet.
FINDSTRING(REVERSE( #[User::Filename]),"\\",2)
- FINDSTRING(REVERSE( #[User::Filename]),"\\",1) - 1 (= 1 in our example)
And there are our three arguments. Putting those all together with your base folder name (and I added a trailing slash. If that doesn't work for you, take it out of there!):
"//FTP//"
+ SUBSTRING(
#[User::Filename] ,
LEN( #[User::Filename]) - FINDSTRING(REVERSE( #[User::Filename]),"\\",2),
FINDSTRING(REVERSE( #[User::Filename]),"\\",2)
-FINDSTRING(REVERSE( #[User::Filename]),"\\",1)-1 )
+ "//"
Evaluates to //FTP//C//.
Now, when the powers that be decide to "clean up" that source server, and the Test2 layer disappears all of a sudden, or things get crazy, and you bury this all one layer deeper, your code will still work.
Side Note
If you're really using drive letters in your file path names, like C:\, be aware that when you're running your packages locally, that's your C:\ drive the package is using, but when you deploy this, it'll be looking around on the server's C:\ drive, and it just might not like what it finds, or more likely, doesn't find there.
I have a problem with the variable %CD% in a batch-file. It adds a backslash if the script is run from the root of a drive.
as an example: updatedir=%CD%\Update & echo %updatedir% will return something like
From a folder E:\New Folder\Update
From a drive root E:\\Update
Is there any way to get rid of the extra backslash if run from root?
Yes %CD% only has a trailing \ if the current directory is the root. You could get rid of any trailing backslash that might be there. But there is a simpler solution.
Use the undocumented %__CD__% instead, which always appends the trailing backslash. This makes it easy to build a clean path, regardless of the current directory.
set "updatedir=%__CD__%Update
You can do something like this:
set "CurrentDir=%CD%"
if "%CD:~-1%"=="\" set "CurrentDir=%CD:~0,-1%"
Since you don't want to go changing the system variable %CD%, this sets a new variable %CurrentDir% to the current value of %CD%. Then, it checks to see if the last character in %CD% is a \, and if it is, sets %CurrentDir% to the value of %CD%, minus the last character.
This question/answer has more information on using substrings in batch files.
replace every occurence of \\ with \.
echo %updatedir:\\=\%
I am using CMake to build my project and I have the following line:
include_directories(${LLVM_INCLUDE_DIRS})
which, after evaluating LLVM_INCLUDE_DIRS, evaluates to:
include_directories(C:\Program Files\LLVM\include)
The problem is that this is being considered two include directories, "C:\Program" and "Files\LLVM\include".
Any idea how can I solve this problem? I tried using quotation marks, but it didn't work.
EDIT: It turned out that the problem is in the file llvm-3.0\share\llvm\cmake\LLVMConfig.cmake. I enclosed the following paths with quotation marks and the problem was solved:
set(LLVM_INSTALL_PREFIX C:/Program Files/LLVM)
set(LLVM_INCLUDE_DIRS ${LLVM_INSTALL_PREFIX}/include)
set(LLVM_LIBRARY_DIRS ${LLVM_INSTALL_PREFIX}/lib)
In CMake,
whitespace is a list separator (like ;),
evaluating variable names basically replaces the variable name with its content and
\ is an escape character (to get the symbol, it needs to be escaped as well)
So, in your example, include_directories(C:\\Pogram Files\\LLVM\\include) is the same as
include_directories( C:\\Program;Files\\LLVM\\include)
that is, a list with two items. To avoid this, either
escape the whitespace as well:
include_directories( C:\\Program\ Files\\LLVM\\include) or
surround the path with quotation marks:
include_directories( "C:\\Program Files\\LLVM\\include")
Obviously, the second option is the better choice as it is
simpler and easier to read and
can be used with variable evaluation like in your example (since the result of the evaluation is then surrounded by quotation marks and thus, treated a single item)
include_directories("${LLVM_INCLUDE_DIRS}")
This works as well, if LLVM_INCLUDE_DIRS is a list of multiple directories because the items in this list will then be explicitly separated by ; so that there is no need for unquoted whitespace as implicit list item separator.
Side note:
When using hard-coded path-names (for whatever reason) in my CMake files, I usually uses forward slashes as directory separators as this works on Windows as well and avoids the need to escape all backslashes.
This is more likely to be an error at the point where LLVM_INCLUDE_DIRS is set rather than a problem with include_directories.
To check this, try calling include_directories("C:\\Program Files\\LLVM\\include") - it should work correctly.
The problem seems to be that LLVM_INCLUDE_DIRS was constructed without using quotation marks. Try for example running this:
set(LLVM_INCLUDE_DIRS C:\\Program Files\\LLVM\\include)
message("${LLVM_INCLUDE_DIRS}")
set(LLVM_INCLUDE_DIRS "C:\\Program Files\\LLVM\\include")
message("${LLVM_INCLUDE_DIRS}")
The output is:
C:\Program;Files\LLVM\include
C:\Program Files\LLVM\include
Note the semi-colon in the first output line. This is a list with 2 items.
So the way to fix this is to modify the way in which LLVM_INCLUDE_DIRS is created.
Can someone explain the syntax in the source attribute here? What the heck is "pack:" and "application:" and why 3 commas? I couldn't find any decent desciptions.
Here's the MS documentation on the Pack URI Scheme
The three commas represents a XAML resource file that is located in the root of the local assembly's project folder.
The packageURI is actually a URI within a URI,so it is encoded by converting its forward
slashes into commas.
Therefore,the triple commas are actually encoded forward slashes.
Also you could replace something like
pack://application:,,,/logo.jpg
with this
/logo.jpg
The runtime will prefix the pack://application:,,,.