[I dropped comp.compilers.lcc from the newsgroups line.]
Reading this thread it is amazing how much negative reaction there is to
this idea.
Possibly because of the person who proposed it, but possibly also
or instead because the idea has been tried before and found wanting.
* This feature requires the programmer to do nothing different
* There is available a new /optional/ function such as fname()
So the programmer can use fname() /or/ can do whatever he does now.
Use of fname() allows retrieval of a filename from any file opened with
fopen() from many millions of lines of existing code with /no changes/ to
those lines (which in some cases may not be accessible anyway).
So what is the problem? (I understand that fname() may be restricted to a
particular implementation.)
There is nothing fundamentally wrong with the idea. As at least
a few people have pointed out, it helps out in the case of files
that were opened by "bad" code ("bad" is somewhat subjective of
course) that fails to save the name even though the name is useful
later. If the implementation saves the name for you, you can work
around the bad code -- rather than fixing it -- in those places
were you want to retrieve the name by which the file was opened.
This part is, I think, straightforward enough and something on
which everyone agrees.
The objections are:
- The name may be "out of date" (due to file renames and so on).
This is of course true, but not really relevant: in a situation
in which you would have saved the name, then printed the one
*you* saved, you would be printing that same out-of-date name.
- The name may be unavailable, because the "fopen()" equivalent
was done in a way that did not provide a name (e.g., via fdopen()
on a system that supports it -- this includes many Windows-based
systems -- or the operation is done on stdin, stdout, or stderr).
This is also true, but again perhaps not so relelvant: in
a situation in which you would have saved the name, then printed
the one *you* saved, you might well have the same problem. (Or
you might not, in the case of fdopen() for instance.) So this
objection is slightly more relevant.
- The "implementation question", as I will call it: how does the
implementation actually implement the name-saving?
A typical stdio "FILE *" pointer points to a structure with a
number of fields that are accessed via macros and/or functions:
typedef struct __sFILE FILE;
struct __sFILE {
... various fields ...
};
The "obvious" way to implement _fname is:
FILE *fopen(const char *restrict name, const char *restrict mode) {
FILE *retval;
... all the usual work ...
... assume we are now ready to succeed here ...
retval->__sname = name;
return retval;
}
const char *_fname(FILE *fp) {
return fp->__sname;
}
The problem with this implementation is that the pointer saved
in fopen(), and returned by _fname(), is valid only as long as
the storage for the name-string passed to fopen(). If -- as is
typical -- the name is in an automatic-duration buffer, the
pointer _fname() will return becomes invalid as soon as that
automatic-duration variable is destroyed. In something reasonably
close to half the calls to fopen(), this has happened by the
time you (the programmer who would use _fname()) would get
around to calling _fname(). So *this* implementation will not
help you.
The implementation can, of course, simply use something similar
to the (nonstandard) strdup() function:
retval->__sname = strdup(name);
return retval;
}
but now the cost is less trivial: the implementor now must not
only add a pointer to each FILE object, but also allocate space
to hold the name. The implementor must also make sure to free()
the space when the FILE is fclose()d.
This objection is not so much an "objection" as a "point of
view". Is it reasonable to have the C library routine do the
strdup() (or equivalent)? If not, is the pointer-only version
of fname() going to be useful enough?
- Lastly, there is the "utility question", which is something of
an expanded version of the previous question. Even if the C
library fopen() routine does do a strdup()-or-equivalent, so
that a non-NULL return from _fname() actually points to a
useable string, is knowing the name alone sufficient? In many
(but not all) cases, a diagnostic that prints only the name of
the file is not terribly useful. If you want to print a file
name and line number, or file name and character offset, or
file name and nearby contents, you need a bit more. The
character offset can be (non-portably, alas) obtained via
fseek(), ftell(), or fgetpos(), but the others require more
forethought and design -- and if you apply this forethought
and design, you do not need _fname().
(Note that when using forethought and design, the programmer
can save the name even when using fdopen(), tell whether or
not there is any need to strdup() the name, update it if the
file is renamed on purpose, and so on. The code also works on
every implementation, not just those that provide _fname().
So this option is a clear winner, if it is an option at all.)
So it really boils down to: a quick-and-dirty save-only-the-pointer
implementation is cheap, but not very useful. A strdup()-the-string
implementation is less cheap, but more useful. In my opinion, the
second version still does not reach the "90% useful" level that makes
it worth adding. The first has lower cost, but does not even make
it to "40% useful" (again in my opinion).