A bug in FileFullName() ?

Started by snowsnowsnow, September 30, 2024, 10:52:56 PM

Previous topic - Next topic

snowsnowsnow

My understanding of FileFullName() is that it is supposed to always produce a fully qualified, absolute filename.  However, there seems to be a problem if you pass it something like "S:file.ext" and the current directory on S: is S:\.

Note: This was tested on a very old version of WB.  If it is fixed in the current version, then that's OK; I'd like to know that, if it is the case.

Now:
1) Suppose the current directory on C: is something like C:\foo\bar.  Then FileFullName("C:file.ext") correctly returns C:\foo\bar\file.ext.

2) But if the current directory on S: is S:\, then FileFullName("S:file.ext") returns "S:file.ext".  I think it should return S:\file.ext.  Note that without the \, you don't have an absolute filename.  If the current directory on S: is later changed, then using the value derived from FileFullName() is now invalid.

Furthermore, I actually became aware of this because I was passing the output of FileFullName() to a sub-program that really requires a fully qualified/absolute filename.  It rejects S:file.ext as invalid input.

I fixed this by coding:

; (insertstring function not shown)
fn = FileFullName(...)
IF StrSub(fn,3,1) != '\' THEN fn = insertstring(fn,3,'\')


td

"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

spl

Tried [from Help File]
DirChange("H:Scripts")
a="active.csv"
b=FileFullname(a)
Message(a,b)
[code]

Got: [attached].
Stan - formerly stanl [ex-Pundit]

td

The FileFullname function treats "<drive letter>:" with no following slash as a relative path and turns the path into an absolute path based on the current directory. I am not sure how long it has behaved the way it does now but the function's last documented change was when Unicode support was added many years ago.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

snowsnowsnow

OK - then maybe it is just a version thing.  No worries; I have my workaround.

And just to be clear, I'm not saying it doesn't work at all; in fact, most of the time, maybe 99% of the time, it does exactly what it should.  I've been using it for a long time.  But it is just this one very specific case, where, in my version of WB, it doesn't do the right thing.

td

If the current WinBatch process lacks a current directory for a passed-in path's drive letter, the function does not add the missing backslash to the path. It would be a bit of an assumption to do so but it possibly should.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

td

Also, the function does not change a path something like "S:..\file.ext" or "S:.\file.ext" when drive "S:" does not have a CWD associated with it. That is expected behavior. Applying the same logic to "S:file.ext" seems to be a reasonable approach. In other words, the FileFullname only produces an absolute path when it can fill in missing information based on the current working directory. 
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

snowsnowsnow

I'm not sure what you mean by "Does not have a CWD associated with it".

Doesn't every valid drive (And, yes, in my situation, S: is a valid network drive) have a CWD?

td

No they don't. A CWD is unique to a process. There are at least 3 ways it can be set:
  • When the program starts the system assigns the startup drive and directory as the CWD.
  • The process can change the CWD. See DirChange.
  • Calling certain shell functions will change the process CWD.

Also, the Windows command shell sets a hidden Environment variable when it is started from a drive. That variable reflects the path you see at the command shell prompt. WinBatch checks the drive letter of the passed in relative path for a matching hidden Environment variable with a matching drive. If it finds one, the path in the variable is used as the drives CWD.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

snowsnowsnow

We may be getting into the weeds here, but I still don't get what you are saying.  BTW, I *am* familiar with how Windows keeps track of the DOS concept of "a current directory for each drive letter" - that is, via "hidden" environment variables.

The point is that if my WB program did a FileOpen() of "S:file.ext", it would succeed, since there is a file out there, in the root of S:, called "file.ext".  So, if I did a FileOpen() of FileFullName("S:file.ext"), that also would succeed, but if I display the output of FileFullName("S:file.ext"), it is "S:file.ext", not "S:\file.ext".

And the point of the previous paragraph, is that the FileOpen() succeeds because S:file.ext is good enough - for FileOpen().  But, it is not "good enough" for the other program (which I have not identified - and no purpose would be served by so doing).  For that other program to work, I need to pass it "S:\file.ext".

I hope this is all clear now.

td

There is no reason to put the word "hidden" in quotes when referring to hidden environment variables. The cmd.exe path variables created by the OS begin with an equal sign (=) which is not a valid character when used in environment variable names. The whole business is a now almost undocumented kludge that has been around since the early days of the Windows OS.

WinBatch does not convert relative paths to absolute paths in functions like FileOpen. The file that is opened is determined by the OS and not WinBatch. That determination can change with the process environment including the OS version. If you use a relative path, you are accepting the associated risk. There are cases where this behavior is the desired outcome. In other words, when you use a relative path with a function like FileOpen you can get completely different results using the same relative path.

The FileFullName function creates an absolute path by a set of rules but does not guess about the path when those rules do not resolve to an absolute path.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

td

The WinBatch documentation for the FileFullName will be updated to reflect the function's operation better.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

spl

Quote from: td on October 03, 2024, 10:38:40 AMThe WinBatch documentation for the FileFullName will be updated to reflect the function's operation better.

Great! Resolves a deeply disturbing file issue.[
Stan - formerly stanl [ex-Pundit]

td

I had no idea you were "deeply disturbed"...
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

snowsnowsnow

QuoteI had no idea you were "deeply disturbed"...

I think he was kidding around.  Implying that this whole thread is much ado about nothing.  And, in a way, it is.  But I am glad to hear that you are going to update the documentation.  That is a Good Thing.

My point is simply that if an arbitrary user expects FileFullName() to always return a fully qualified pathname string, there is (at least) one edge case where it won't do that.  Therefore, my little fix (of injecting the missing backslash into position 3 of the returned string if it is not already there) is a necessary workaround.

FWIW, I think you are right, that the underlying problem is that the needed environment variable is not set, so FileFullName() doesn't know what to inject, so it injects nothing.  But this begs the question of "Why?  Why isn't the env var there?  Shouldn't it be there (for all currently valid drives)?"

Anyway, that's all I was trying to accomplish by starting this thread.

Note also: I tested this some more on a different Windows machine, and found that the problem does not present for either C: (when the cwd of C: is set to C:\) or Q: (A network drive mapped to a Samba share), but it did on T: (A SUBST drive mapped to C:\somedirectory).  So, there is that...

td

I think we were both having some fun (at least, I hope that is the case.)

But after giving it some more thought your argument involving consistency has merit. Also, you can set your hidden environment variable that causes FileFullName to add a backslash. Using your example drive:

; H must be a valid drive letter.
EnvironSet("=H:","H:\")
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

spl

Quote from: td on October 03, 2024, 03:09:56 PMI think we were both having some fun (at least, I hope that is the case.)

NP there. I think Snow made a valid point or I wouldn't have checked it out in the first place. I have done a bit of file processing in PS, and WB is a lot simpler to work with. PS uses System.Windows.Forms.OpenFileDialog and this post piqued my interest in how PS works with file elements.  You begin something like
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property @{
    InitialDirectory =  "H:scripts"
    Filter = 'Text Files (*.csv;*.txt)|*.csv;*.txt'
    Title = 'Select File To Process'
}
$result = $FileBrowser.ShowDialog()
if ($result -eq 'Cancel') { Exit }

and if a file is selected it is assigned to $FileBrowser. To break that down, I would use something like
$FullFile = $FileBrowser.FileName
$FileName = $FileBrowser.SafeFileName
$parent = Split-Path -Path $FullFile -Parent
$parentslash = (Split-Path -Path $FullFile -Parent) + "\"
$ext = (Split-Path -Path $FullFile -Leaf).Split(".")[1]
$extdot = (Get-Item $FullFile).Extension
"FullFile: " +$FullFile
"FileName: " + $FileName
"parent: " +$parent
"parentslash: " +$parentslash
"ext: " +$ext
"extdot: " +$extdot

which would display
FullFile: H:\scripts\InstalledApps.csv
FileName: InstalledApps.csv
parent: H:\scripts
parentslash: H:\scripts\
ext: csv
extdot: .csv

So, again... WB file processing is much cleaner and allows Plan-B's like Snow posted.
Stan - formerly stanl [ex-Pundit]

snowsnowsnow

(O/T)  It is amazing how much PS looks like Perl.  I assume the designers of PS were influenced by Perl.

Both (PS & Perl), BTW, being languages I know almost nothing about (and want it to stay that way).

Note, BTW, that I have written (non-trivial) Perl scripts - just enough to know how much I dislike it.

spl

Quote from: snowsnowsnow on October 04, 2024, 09:28:06 AM(O/T)  It is amazing how much PS looks like Perl.  I assume the designers of PS were influenced by Perl.


I think PS is more like Python. In a previous thread I illustrated how much WB CLR code could profit from PS all of which is a moot point.
Stan - formerly stanl [ex-Pundit]

snowsnowsnow

Just out of curiosity, why is it "moot" ?

The dollar signs in the variable names is Perl-ish, as is the calling syntax.

Also, to be Python-ish, it'd have to use indentation instead of braces.  Does PS do that?

spl

Quote from: snowsnowsnow on October 04, 2024, 02:45:16 PMJust out of curiosity, why is it "moot" ?
The dollar signs in the variable names is Perl-ish, as is the calling syntax.
Also, to be Python-ish, it'd have to use indentation instead of braces.  Does PS do that?

I would say 'moot' as choice of scripting or programming language involves more than appearance, i.e. indents or $ preceding a variable. For example:
Syntax: The syntax of Perl and PowerShell differs significantly.
Perl follows a more concise and compact syntax with its use of regular expressions,
making it well-suited for text processing and pattern matching.
On the other hand, PowerShell has a more verbose and expressive syntax,
resembling the syntax of traditional programming languages like C#,
which makes it easier to read and understand for non-programmers.

Data Types: Perl and PowerShell have different approaches to data types.
Perl is dynamically typed, meaning that variables can hold different types of data
at different points in the program execution. It provides flexible constructs
to work with variables and arrays. In contrast, PowerShell follows a strong and static typing system,
where variables and their data types are defined explicitly.
This makes PowerShell more suitable for tasks requiring type safety and prevention of type-related errors.

Functionality: Perl and PowerShell have different primary domains of application.
Perl is predominantly used for text processing, regular expressions, and system administration tasks,
offering powerful capabilities for file operations, text manipulation, and pattern matching.
PowerShell, on the other hand, was specifically designed for system administration and automation,
providing rich functionality for managing Windows environments, interacting with the .NET framework,
and executing complex administrative tasks.

Script Execution: Perl and PowerShell have different execution models. Perl scripts are usually interpreted,
meaning the Perl interpreter reads the script line by line and executes it in real-time.
PowerShell, on the other hand, is based on the .NET framework and uses the Common Language Runtime (CLR).
PowerShell scripts are compiled into an intermediate language (IL) and can be executed by the CLR.
This compilation step improves the performance of PowerShell scripts, especially when they are executed repeatedly.

you could compare PS and Python in a similar fashion.
Stan - formerly stanl [ex-Pundit]

snowsnowsnow

(Meta/OT)

The word "moot" means different things to different people.  This phenomenon has been well-documented (by people who study these sorts of things).

spl

Quote from: snowsnowsnow on October 05, 2024, 03:25:52 AM(Meta/OT)

The word "moot" means different things to different people.  This phenomenon has been well-documented (by people who study these sorts of things).

Well, most of what I have read, or used in the past, moot=> it is open for debate or discussion. I don't understand what you mean by different people.
Stan - formerly stanl [ex-Pundit]

snowsnowsnow

It is one of those words that has come to mean, in popular parlance, something completely different from what it really means.  There are many examples of this; one chosen (by me) entirely at random is the word "decimate".

And the worst part of it is that they sometimes are able to get the dictionary people to adjust to fit the popular meaning.

spl

Quote from: snowsnowsnow on October 05, 2024, 09:55:06 AMIt is one of those words that has come to mean, in popular parlance, something completely different from what it really means.  There are many examples of this; one chosen (by me) entirely at random is the word "decimate".

And the worst part of it is that they sometimes are able to get the dictionary people to adjust to fit the popular meaning.

Who are 'they'... probably should look up 'conspiracy theory'
Stan - formerly stanl [ex-Pundit]