Getting the file name from a FILE *

B

Bartc

Ian Collins said:
jacob navia wrote:
Quite, the disk region is distinct from one of its possible names. As
others have said, the name my change or the file may not have a name
after it is opened.

A FILE is a data source and or sink, the name is immaterial.

The name is important enough for the OS to store it with each file. All
those dir/ls listings would be really confusing if all you saw was block
numbers.

Now, there may be OS's striving hard to avoid the 1:1 correspondence between
disk region and filename that would otherwise make things far too simple for
programmers. But this /is/ for Windows.
In most
code I've seen or written, the only place where the name is important is
the place where the file is opened.

The name is important to the end-user, if it's a file he cares about (or, if
it goes wrong, even if he doesn't).
A buffer has to be allocated and and the name copied. True this may
take a trivial time compared with opening a disk file, but not compared
to opening a (FLASH) memory based file.

If flash memory is slower, the name-handling overhead would be even more
trivial.
 
D

Dik T. Winter

> It makes sense in most applications, specially when you write
> a library and you receive a FILE pointer, and you want to
> write a more comprehensible error message than:
> fprintf(stderr,"Can't write to file %p\n",file);

It would be completely obscure if the filename does not contain the
complete path. Where in the file system does the program want to
write? What can I do to correct it?
 
W

Walter Roberson

The name is important enough for the OS to store it with each file. All
those dir/ls listings would be really confusing if all you saw was block
numbers.

I don't recall that I have encountered even a single Unix filesystem that
stored the file name with each file: each of them that I have
seen has segregated the name from the information about the file
(ownership, size, location of information on the disk), and most of them
have allowed multiple names to relate to the same file.
Now, there may be OS's striving hard to avoid the 1:1 correspondence between
disk region and filename that would otherwise make things far too simple for
programmers. But this /is/ for Windows.

But you said "dir/ls listings". Did Windows adopt "ls" as a command
somewhere along the way? And did the NTFS filesystem lose
"directory junctions", "hard links", and "single instance storage" ?
 
W

Walter Roberson

Richard Heathfield said:
The nice thing about C is
that you pay for what you ask for, and nothing else. The fopen function
just opens the file, and that's all. No hidden overheads - *at all*.

That would depend very much on what you consider to be an "overhead".
For example on any POSIX system, it is required that the file
access-time be updated when the file is opened (unless the filesystem
is read-only). Access-time and last-changed-time and the like
wre unwanted / unnessary overheads in some situations.

True this is a POSIX behaviour rather than a C fopen() mandated
behaviour, but I believe it still is enough to establish
a counter argument to the "at all" part of "No hidden overheads - *at all*"
 
P

Peter Nilsson

Keith said:
I mildly prefer "fname". I strongly suggest that it *not* be
declared in <stdio.h>, even in non-conforming mode.

Obviously it shouldn't be declared in conforming mode, but
clearly the function is synonymous with said:
It assumes that each stream is associated with exactly one
file name.

No, it assumes you pass exactly one file name to fopen() [or
freopen().]
That's not unreasonable!
Depending on the system, some streams are not
associated with any named file,

By default (until freopen say) I return "stdin" for stdin, etc...
and some many have multiple equally valid names.

But that's not what FileName is capturing.
There are a number of decisions you'd have to make *and
document* about the form of the name.

So 7.19.3p8 says, but I don't see why that's important to fname()
which simply returns what was passed to fopen(). [Or something
like it; truncated to FILENAME_MAX-1 characters in my case.]
For Windows, you've already specified
lower case, which isn't necessarily ideal.

I think Jacob was simply referring to the lower case of the
function name "fname". FNAME() would look out of place
against fopen, fwrite etc...
Other possibilities are the name used to open it, ...

That's what he's proposing.
Does the Windows API already provide something like this?

The point is that <stdio.h> doesn't.

In my own case, rather than modify the C library, I have an
alternate header that wraps over <stdio.h> to provider a
filename and other things. The filename part is certainly
implementable in pure ISO C.

I'm pretty sure if it was available in C89, it would be in
significant use. Although I can understand why it wasn't
standardised.
 
B

Ben Bacarisse

CBFalconer said:
Peter Nilsson wrote:
<snip>

And I am safe in snipping most of the stuff that you left because you
had already removed all of the text form Peter Nilsson that explained
away your objections. Of course, that makes this reply of mine
unintelligible by your rules, but you did the cutting, not me.
Very simple.

Yes, he explained a simple-to-implement semantics for the function in
question but I doubt you intended to agree with him. Did you
miss-read the last sentence as "I *can't* understand why is wasn't
standardised"?
It is IMPOSSIBLE to provide in general, and
particularly on the heart systems using C, i.e. Linux/Unix/Posix.
Files on these systems have no particular name, and the name to a
user is assigned by a link to the file, kept in some directory.
The number of links, and names, is unlimited.

Please lets not go round this again. You cut from your reply all the
parts where Peter explained how simple it would be. That fact that
one can't implement the semantics that *you* think the mechanism
should have is neither here nor there. Of course, you could object
to the semantics that Peter was suggesting, but you did not do that
either.

The real objection to this idea is that will draw people in to using a
non-standard extension. Also, if copying is involved, that it imposes
a penalty, though it would be simple to turn it all off (including any
overhead) if compiling in standards mode.
 
J

jacob navia

CBFalconer said:
If you just want the name under which the file was opened, save
that at fopen time. No load on the library, no muss, no fuss. See
the strcpy function.

Yes sure. And how do the other functions that need this information
will be able to get it????

Suppose

int readfromLog(FILE *fp)
{
char buf[512];
size_t bufsiz=sizeof(buf);
int s = fread(buf,1,bufsiz,fp);
if (s <= 0) {
// How do I get the name of the file here Mr Falconer?
}
}

You see the problem?

Now ALL the interfaces to ALL the functions that could need this
information (or that call a function that could need this
information) need their interface CHANGED to have ONE EXTRA PARAMETER!

This is completely impossible to do in complex systems!
 
C

Chris Dollin

CBFalconer said:
Very simple. It is IMPOSSIBLE to provide in general, and
particularly on the heart systems using C, i.e. Linux/Unix/Posix.
Files on these systems have no particular name, and the name to a
user is assigned by a link to the file, kept in some directory.
The number of links, and names, is unlimited.

If you just want the name under which the file was opened, save
that at fopen time.

That doesn't help ONE LITTLE BIT if some OTHER piece of code
NOT UNDER YOUR CONTROL fopened the file and plopped the FILE*
somewhere. In that case everyone's RANTING that YOU CAN DO IT
YOURSELF is revealed as a FINE CASE OF missing the POINT;
you /can't/ do it yourself, because in general you can't
refactor all the code.
 
V

vippstar

CBFalconer said:
If you just want the name under which the file was opened, save
that at fopen time. No load on the library, no muss, no fuss. See
the strcpy function.

Yes sure. And how do the other functions that need this information
will be able to get it????

Suppose

int readfromLog(FILE *fp)
{
char buf[512];
size_t bufsiz=sizeof(buf);
int s = fread(buf,1,bufsiz,fp); fread returns size_t, not int.
if (s <= 0) { This 'if' is not meaningful
// How do I get the name of the file here Mr Falconer?
}

}

You see the problem?
With the current design of readfromLog? I see three problems!
Now ALL the interfaces to ALL the functions that could need this
information (or that call a function that could need this
information) need their interface CHANGED to have ONE EXTRA PARAMETER!

This is completely impossible to do in complex systems!
No it's not.
You'd simply design readfromLog differently:

int readfromLog(MYFILE *fp)
{
/* ... */
if(s <= 0) {
fp->name ...


Come on Mr Navia, do you honestly believe that this is a serious/hard
issue to solve for a complex system programmer?
 
B

Ben Bacarisse

jacob navia said:
Yes sure. And how do the other functions that need this information
will be able to get it????

I am sure you know the answer to that.
Suppose

int readfromLog(FILE *fp)
{
char buf[512];
size_t bufsiz=sizeof(buf);
int s = fread(buf,1,bufsiz,fp);
if (s <= 0) {
// How do I get the name of the file here Mr Falconer?
}
}

You see the problem?

I think most people here understand the problem and your intent. The
problem is that those of us who have solved it have done so already in
a portable way and your solution will tie people in to one
implementation.
Now ALL the interfaces to ALL the functions that could need this
information (or that call a function that could need this
information) need their interface CHANGED to have ONE EXTRA
PARAMETER!

Not necessarily. The most common solution is to wrap a FILE * in a
struct that has the extra data. In several programs of mine, the name
is not enough -- I need line number information as well -- so your
solution is only a partial one for that use case.
This is completely impossible to do in complex systems!

That is over-stating the case. It is not impossible. If you know of
anyone who believes this and has money to spare, let me know.
 
V

vippstar

That doesn't help ONE LITTLE BIT if some OTHER piece of code
NOT UNDER YOUR CONTROL fopened the file and plopped the FILE*
somewhere. In that case everyone's RANTING that YOU CAN DO IT
YOURSELF is revealed as a FINE CASE OF missing the POINT;
you /can't/ do it yourself, because in general you can't
refactor all the code.
In that case you expect that OTHER piece of code to also save the
filename, IF it is ever going to be needed.
If it is indeed going to be needed but the OTHER piece of code does
not save it, then it's most likely bad code.
When I use code from someone else, a library for example, I expect him
to have thought out all the design issues.
If he has not done so, I can either e-mail him about it, contribute
code, use it as is, or move on to the next library.
I /won't/ expect my compiler to have feature X to save me.
 
B

Bartc

Ben said:
jacob navia <[email protected]> writes:
Not necessarily. The most common solution is to wrap a FILE * in a
struct that has the extra data. In several programs of mine, the name

That is over-stating the case. It is not impossible. If you know of
anyone who believes this and has money to spare, let me know.

If you're distributing a library of some kind (it could be dynamic or
static), and want to update one of the functions so that it can make use of
the filename of a file-handle, then your solution would involve all the
thousands of users of your library in updating their code.

By building in the new capability to FILE, only relinking is needed; you can
leave millions of lines of code untouched. So it's not impossible, but may
not be practical.

If the file functions are in a dynamic library anyway, possibly not even
that is needed, and the new functionality doesn't even need a programmer,
just a download of a library.
 
J

jacob navia

CBFalconer said:
If you just want the name under which the file was opened, save
that at fopen time. No load on the library, no muss, no fuss. See
the strcpy function.
Yes sure. And how do the other functions that need this information
will be able to get it????

Suppose

int readfromLog(FILE *fp)
{
char buf[512];
size_t bufsiz=sizeof(buf);
int s = fread(buf,1,bufsiz,fp); fread returns size_t, not int.
if (s <= 0) { This 'if' is not meaningful
// How do I get the name of the file here Mr Falconer?
}

}

You see the problem?
With the current design of readfromLog? I see three problems!
Now ALL the interfaces to ALL the functions that could need this
information (or that call a function that could need this
information) need their interface CHANGED to have ONE EXTRA PARAMETER!

This is completely impossible to do in complex systems!
No it's not.
You'd simply design readfromLog differently:

int readfromLog(MYFILE *fp)
{
/* ... */
if(s <= 0) {
fp->name ...


Come on Mr Navia, do you honestly believe that this is a serious/hard
issue to solve for a complex system programmer?

Nothing of course. Nothing.

A good systems programmer will
1) Change all calls that use FILE to use MYFILE

Then, change all calls to fread/fwrite to
fread (... fp->file);
and NOT
fread(..., fp);

THEN

determine which libraries need a FILE * and change all calls to
libraries to get fp->file instead of fp

Obviously yours is a very simple solution that can be done
in a minute. My solution, that needs

name = _fname(fp);

is much too complicated and needs too much work/effort.
 
V

vippstar

CBFalconer wrote:
If you just want the name under which the file was opened, save
that at fopen time. No load on the library, no muss, no fuss. See
the strcpy function.
Yes sure. And how do the other functions that need this information
will be able to get it????
Suppose
int readfromLog(FILE *fp)
{
char buf[512];
size_t bufsiz=sizeof(buf);
int s = fread(buf,1,bufsiz,fp); fread returns size_t, not int.
if (s <= 0) { This 'if' is not meaningful
// How do I get the name of the file here Mr Falconer?
}
}
You see the problem?
With the current design of readfromLog? I see three problems!
Now ALL the interfaces to ALL the functions that could need this
information (or that call a function that could need this
information) need their interface CHANGED to have ONE EXTRA PARAMETER!
This is completely impossible to do in complex systems!
No it's not.
You'd simply design readfromLog differently:
int readfromLog(MYFILE *fp)
{
/* ... */
if(s <= 0) {
fp->name ...
Come on Mr Navia, do you honestly believe that this is a serious/hard
issue to solve for a complex system programmer?

Nothing of course. Nothing.

A good systems programmer will
1) Change all calls that use FILE to use MYFILE

Then, change all calls to fread/fwrite to
fread (... fp->file);
and NOT
fread(..., fp);

THEN

determine which libraries need a FILE * and change all calls to
libraries to get fp->file instead of fp

Obviously yours is a very simple solution that can be done
in a minute. My solution, that needs

name = _fname(fp);

is much too complicated and needs too much work/effort.

So you are adding features to your compiler to save your users some
typing?
Why don't you write a text editor instead of a compiler Mr Navia?
 
R

Richard

CBFalconer wrote:
If you just want the name under which the file was opened, save
that at fopen time. No load on the library, no muss, no fuss. See
the strcpy function.
Yes sure. And how do the other functions that need this information
will be able to get it????

int readfromLog(FILE *fp)
{
char buf[512];
size_t bufsiz=sizeof(buf);
int s = fread(buf,1,bufsiz,fp);
fread returns size_t, not int.
if (s <= 0) {
This 'if' is not meaningful
// How do I get the name of the file here Mr Falconer?
}

You see the problem?
With the current design of readfromLog? I see three problems!
Now ALL the interfaces to ALL the functions that could need this
information (or that call a function that could need this
information) need their interface CHANGED to have ONE EXTRA PARAMETER!
This is completely impossible to do in complex systems!
No it's not.
You'd simply design readfromLog differently:
int readfromLog(MYFILE *fp)
{
/* ... */
if(s <= 0) {
fp->name ...
Come on Mr Navia, do you honestly believe that this is a serious/hard
issue to solve for a complex system programmer?

Nothing of course. Nothing.

A good systems programmer will
1) Change all calls that use FILE to use MYFILE

Then, change all calls to fread/fwrite to
fread (... fp->file);
and NOT
fread(..., fp);

THEN

determine which libraries need a FILE * and change all calls to
libraries to get fp->file instead of fp

Obviously yours is a very simple solution that can be done
in a minute. My solution, that needs

name = _fname(fp);

is much too complicated and needs too much work/effort.

So you are adding features to your compiler to save your users some
typing?
"indeed"

Why don't you write a text editor instead of a compiler Mr Navia?

If he does, maybe you could use it? The layout of your replies is
awful. You leave no white space after the quoted material and then put
gratuitous breaks everywhere.

But I'm interested in whose sock puppet you are. You seem to delight in
prancing around putting people down. Not quite as much as your master,
but pretty revolting behaviour nonetheless "Mr" Vippstar.
 
C

Cesar Rabak

jacob navia escreveu:
CBFalconer said:
If you just want the name under which the file was opened, save
that at fopen time. No load on the library, no muss, no fuss. See
the strcpy function.

Yes sure. And how do the other functions that need this information
will be able to get it????

Suppose

int readfromLog(FILE *fp)
{
char buf[512];
size_t bufsiz=sizeof(buf);
int s = fread(buf,1,bufsiz,fp);
if (s <= 0) {
// How do I get the name of the file here Mr Falconer?
}
}

You see the problem?

Also to comment Chris Dollin's remark. The idiomatic way of doing this
is not to write the name of the file in the body of 'if' but instead
construct the readfromLog() interface in a way it returns error codes
which are processed by the caller.

Also, the function [_]fname as proposed would have serious problems if
you attempt to use it in a POSIX environment where FILE *fmemopen() or
FILE *open_memstream() are expected to exist and they have no name
assosiated with.

My humble suggestion is you either use for Windows the already suggested
API as the effort to have a full functioning [_]fname() is all platforms
would not be worth of it.

My .0199999....
 
S

Serve Lau

Chris Dollin said:
That doesn't help ONE LITTLE BIT if some OTHER piece of code
NOT UNDER YOUR CONTROL fopened the file and plopped the FILE*
somewhere. In that case everyone's RANTING that YOU CAN DO IT
YOURSELF is revealed as a FINE CASE OF missing the POINT;
you /can't/ do it yourself, because in general you can't
refactor all the code.

that only works if that code is also written with lcc....

// function using MSVC runtime you have no control over
FILE *openfile(const char *file);

// function used in lcc
FILE *fp = openfile("test");
if (fp != NULL)
{
printf("%s\n", fname(fp));
}

How stable is this code??? it compiles fine with no warnings.

Or did you mean with code you have no control over that the one who
maintains the software containing openfile is working in the same company?
You have learnt to talk. If you are too afraid to ask them to change it you
can still do it yourself.

MYFILE f;
f.name = "test.txt";
f.fp = openfile(f.name);

that wasnt so hard to do even when you dont have control over openfile
 
J

jacob navia

Cesar said:
jacob navia escreveu:
CBFalconer said:
If you just want the name under which the file was opened, save
that at fopen time. No load on the library, no muss, no fuss. See
the strcpy function.

Yes sure. And how do the other functions that need this information
will be able to get it????

Suppose

int readfromLog(FILE *fp)
{
char buf[512];
size_t bufsiz=sizeof(buf);
int s = fread(buf,1,bufsiz,fp);
if (s <= 0) {
// How do I get the name of the file here Mr Falconer?
}
}

You see the problem?

Also to comment Chris Dollin's remark. The idiomatic way of doing this
is not to write the name of the file in the body of 'if' but instead
construct the readfromLog() interface in a way it returns error codes
which are processed by the caller.

Then the same problem will appear in the caller. You will have to keep
that information in a associative list (or in a structure containing the
file) , then modify a lot of interfaces to pass an extra parameter or
a different structure than FILE *.

This is not possible when you are writing a library (and can't ask the
user to pass you the file name because the user may not know it, or
did not store it, etc)

This is a discussion where the principle of keeping related information
in one place holds. The best place to keep the file name information is
in the fopen function since it is that function the constructor of
the FILE structure. Any other solution means a replication of effort
that should be done when constructing the object.
Also, the function [_]fname as proposed would have serious problems if
you attempt to use it in a POSIX environment where FILE *fmemopen() or
FILE *open_memstream() are expected to exist and they have no name
assosiated with.

How many times must I repeat the same thing? If there is no file name
you can always return NULL (meaning there is no file name) or some
made up name like "/\/\stdin/\/\"...
 
I

Ian Collins

jacob said:
(e-mail address removed) wrote:

Nothing of course. Nothing.

A good systems programmer will
1) Change all calls that use FILE to use MYFILE

Then, change all calls to fread/fwrite to
fread (... fp->file);
and NOT
fread(..., fp);

THEN

determine which libraries need a FILE * and change all calls to
libraries to get fp->file instead of fp

Obviously yours is a very simple solution that can be done
in a minute. My solution, that needs

name = _fname(fp);

is much too complicated and needs too much work/effort.
Find a decent refactoring editor, or use a platform with decent command
line tools to do the same job.
 
C

Cesar Rabak

jacob navia escreveu:
Cesar said:
jacob navia escreveu:
CBFalconer wrote:
If you just want the name under which the file was opened, save
that at fopen time. No load on the library, no muss, no fuss. See
the strcpy function.


Yes sure. And how do the other functions that need this information
will be able to get it????

Suppose

int readfromLog(FILE *fp)
{
char buf[512];
size_t bufsiz=sizeof(buf);
int s = fread(buf,1,bufsiz,fp);
if (s <= 0) {
// How do I get the name of the file here Mr Falconer?
}
}

You see the problem?

Also to comment Chris Dollin's remark. The idiomatic way of doing this
is not to write the name of the file in the body of 'if' but instead
construct the readfromLog() interface in a way it returns error codes
which are processed by the caller.

Then the same problem will appear in the caller. You will have to keep
that information in a associative list (or in a structure containing the
file) , then modify a lot of interfaces to pass an extra parameter or
a different structure than FILE *.

It is up to the user of the functionality you're creating to do what it
finds appropriate.

It would be a diversion from the main topic to be finicky on the example
you gave, but just to avoid abstractions: in the case of hypothetical
readFromLog(), how many logs would be in an application? Isn't easier to
the programmer call the function with a wrapper readUsersLog,
readMaterialsLog, etc., and then just give a hard coded (in the wrapper)
"Error reading users log.", etc.?
This is not possible when you are writing a library (and can't ask the
user to pass you the file name because the user may not know it, or
did not store it, etc)

My central comment and critic here is that your design of the library is
not correct.

In some place was this file opened and the name known, the common way of
doing in C is to get back to caller.
This is a discussion where the principle of keeping related information
in one place holds. The best place to keep the file name information is
in the fopen function since it is that function the constructor of
the FILE structure. Any other solution means a replication of effort
that should be done when constructing the object.

A FILE structure can be obtained without a name. . .
Also, the function [_]fname as proposed would have serious problems if
you attempt to use it in a POSIX environment where FILE *fmemopen() or
FILE *open_memstream() are expected to exist and they have no name
assosiated with.

How many times must I repeat the same thing? If there is no file name
you can always return NULL (meaning there is no file name) or some
made up name like "/\/\stdin/\/\"...

So how the user will know *what* NULL object is being the culprit? In
the large what would be the advantage?

If your library requires a set of functions you feel to report file
names, create a whole ensemble with the correct ones from start, like
(say) MYFILE *openLog(), int readFromLog(), int closeLog(), etc.

Better, less surprises for users that want a conforming program to run
compiled by your tools, and you have the API you're developing.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,218
Latest member
JolieDenha

Latest Threads

Top