• Print

Author Topic: FILEATTR  (Read 1751 times)

Galleon

  • Administrator
  • Hero Member
  • *****
  • Posts: 4664
  • QB Forever
    • Email
FILEATTR
« on: December 04, 2009, 02:27:42 AM »
No work has been done on this command yet.
Something old... Something new... Something borrowed... Something blue...

Clippy

  • Hero Member
  • *****
  • Posts: 16427
  • I LOVE π = 4 * ATN(1)    Use the QB64 WIKI >>>
    • Pete's Qbasic Site
    • Email
Re: FILEATTR
« Reply #1 on: December 09, 2009, 03:58:00 PM »
FILEATTR is used to check the current file open mode and can also return the DOS file handle.

A programmer does not need the OPEN mode normally as they should know the mode at the current time.

However, the DOS handle could be useful if the OS even supports DOS. I wonder how long that will last?

Ted
QB64 WIKI: Main Page
Download Q-Basics Code Demo: Q-Basics.zip
Download QB64 BAT, IconAdder and VBS shortcuts: QB64BAT.zip
Download QB64 DLL files in a ZIP: Program64.zip

rpgfan3233

  • Guest
Re: FILEATTR
« Reply #2 on: January 10, 2010, 08:39:32 AM »
This can't be implemented completely without changing the way file handling works in QB64.  Currently QB64 uses a std::fstream object from the standard C++ library to store the actual file.  POSIX provides the necessary C APIs, but there isn't a way to convert a C++ std::fstream object to a FILE pointer for use with the C APIs because C++ doesn't guarantee that the std::fstream implementation uses a FILE pointer internally.  In addition, C++ didn't want to restrict the implementation details of files, so it doesn't provide any sort of "fd" member to return the file descriptor as an integer because the file may not be associated with an integral descriptor in some OS.  As a result, FILEATTR(filenum, 2) can't be implemented.

However, there is nothing preventing the implementation of FILEATTR(filenum, 1), which returns the mode used in the OPEN statement with the specified QB file number.  The OPEN mode is returned as one of the following integers:

1 - INPUT
2 - OUTPUT
4 - RANDOM
8 - APPEND
32 - BINARY

I discovered this information when searching for a way to implement this.  I was able to implement the function when the attribute parameter (the second one) of the FILEATTR function is set to 1, but because of the cross-platform nature of C++, I was unable to find a way to implement the rest of the function when attribute is set to 2 due to this specific abstraction in the language.

Pete

  • Moderator
  • Hero Member
  • *****
  • Posts: 6240
  • Cuz I sez so varmint!
Re: FILEATTR
« Reply #3 on: January 10, 2010, 12:18:43 PM »
FILEATTR works just fine AS IS in QB64...

Of course, it thinks it is a multi-dimensional array at this point, but WHOGAS!  ;D
----------------------


Well good catch on the DOS file handle C conversion problem. The only practical purpose for that is to return the number of files that are in use. QB64 eliminates the need to count them, in regard to over-use, and I wonder what other practical purposes knowing either the order the file was opened in or how many files are currently open this statement attribute "2" would be good for.

Note in QuickBasic or QB the code below will bomb at i = 16 and return a file not found error. Updating the FILE statement in the config.sys or config.nt (XP and above in the Windows\system32 folder) will allow for more than 16 files files to be open at the same time.

Code: [Select]
CLS
FOR i = 1 TO 100
OPEN "xyz.txt" FOR INPUT AS #i
NEXT
DO
a = FILEATTR(i, 1)
b = FILEATTR(i, 2)
DO: LOOP UNTIL INKEY$ <> ""
PRINT a, b
LOOP

I suppose a function could be written that the compiler could add to keep track of the file open order but I don't have a clue how to audit the system to see when a file is opened. You certainly can't depend on program flow for this function.

Frankly, as far as the attribute, I've never found a use for that either, and I've worked with hyndreds of file apps and networking and I never found a use for FILEATTR. I suppose that if a person wanted to assign an array to the file name and then have the computer show the file name and status on the screen, FILEATTR would be useful for that. I suppose a conditional statement might be able to use it... if a file is open for append then go do something, etc.

Code: [Select]
CLS
PRINT " 1) Open for input"
PRINT " 2) Open for output"
PRINT " 3) Open for append"
PRINT
INPUT " What would you like to do with your file? ", choice
SELECT CASE choice
CASE 1: OPEN "xyz.txt" FOR INPUT AS #1
CASE 2: OPEN "xyz.txt" FOR OUTPUT AS #1
CASE 3: OPEN "xyz.txt" FOR APPEND AS #1
END SELECT
PRINT
a = FILEATTR(1, 1)
ON a GOSUB 100, 200, 0, 0, 0, 0, 0, 300
SYSTEM
0 PRINT " What the hell went wrong!"
100 PRINT " File was opened for input": RETURN
200 PRINT " File was opened for output": RETURN
300 PRINT " File was opened for append": RETURN

Anyway, something like this will neeed to be made up as an example for the wiki. The trouble is, it just teaches bad coding habits, in my opinion, as the SELECT CASE argument could have been used directly to handle the conditions in the example given above.

Priority-wise, this one should be low on the pole and I sure hope it doesn't create too  much brain strain. The Networking support with LOCK/UNLOCK (In the works), the default  ability to open more than 16 files without modifying system files (Inherent in QB64) and the newly added TCP/IP are much more needed in modern applications.

Pete
It's only rocket science; it's not Linux!

Clippy

  • Hero Member
  • *****
  • Posts: 16427
  • I LOVE π = 4 * ATN(1)    Use the QB64 WIKI >>>
    • Pete's Qbasic Site
    • Email
Re: FILEATTR
« Reply #4 on: January 10, 2010, 12:22:04 PM »
Well, I NEVER used it ever. I knew the OPEN modes because I programmed them. I never had a need for the DOS handle either. I could use Interrupt &H21 for that when a procedure required it.

QB64 returns different info for VER and ENVIRON$ too.

File access may have to be different too. I don't know if Interrupt will ever be able to work with files either. It's a big jump from DOS or NTVDM to Windows.

Ted

I see the LOCK campaign is in full gear.  ;D
QB64 WIKI: Main Page
Download Q-Basics Code Demo: Q-Basics.zip
Download QB64 BAT, IconAdder and VBS shortcuts: QB64BAT.zip
Download QB64 DLL files in a ZIP: Program64.zip

qbguy

  • Full Member
  • ***
  • Posts: 239
Re: FILEATTR
« Reply #5 on: January 10, 2010, 06:57:41 PM »
Quote from: Pete on January 10, 2010, 12:18:43 PM

Priority-wise, this one should be low on the pole and I sure hope it doesn't create too  much brain strain. The Networking support with LOCK/UNLOCK (In the works), the default  ability to open more than 16 files without modifying system files (Inherent in QB64) and the newly added TCP/IP are much more needed in modern applications.

Pete

The solution for LOCK has the same problem of how to get the file descriptor from the stream (the solution I used is nonportable).  However, this should not be a problem as Galleon said he plans to switch QB64 to stdio or POSIX anyway, and there is a standardized way to get the file descriptor from a C FILE * (namely fileno); and the rest of the code is the important part -- showing how to lock the file using fcntl and LockFile.

EDIT: This should work for getting the file descriptor from a C++ stream across versions of GCC (uggh)
Code: [Select]
#include <cstdio>  // declaration of ::fileno
#include <fstream>  // for basic_filebuf template
#include <cerrno>

#if defined(__GLIBCXX__) || (defined(__GLIBCPP__) && __GLIBCPP__>=20020514)  // GCC >= 3.1.0
# include <ext/stdio_filebuf.h>
#endif
#if defined(__GLIBCXX__) // GCC >= 3.4.0
# include <ext/stdio_sync_filebuf.h>
#endif

//! Similar to fileno(3), but taking a C++ stream as argument instead of a
//! FILE*.  Note that there is no way for the library to track what you do with
//! the descriptor, so be careful.
//! \return  The integer file descriptor associated with the stream, or -1 if
//!   that stream is invalid.  In the latter case, for the sake of keeping the
//!   code as similar to fileno(3), errno is set to EBADF.
//! \see  The <A HREF="http://www.ginac.de/~kreckel/fileno/">upstream page at
//!   http://www.ginac.de/~kreckel/fileno/</A> of this code provides more
//!   detailed information.
template <typename charT, typename traits>
inline int
fileno_hack(const std::basic_ios<charT, traits>& stream)
{
    // Some C++ runtime libraries shipped with ancient GCC, Sun Pro,
    // Sun WS/Forte 5/6, Compaq C++ supported non-standard file descriptor
    // access basic_filebuf<>::fd().  Alas, starting from GCC 3.1, the GNU C++
    // runtime removes all non-standard std::filebuf methods and provides an
    // extension template class __gnu_cxx::stdio_filebuf on all systems where
    // that appears to make sense (i.e. at least all Unix systems).  Starting
    // from GCC 3.4, there is an __gnu_cxx::stdio_sync_filebuf, in addition.
    // Sorry, darling, I must get brutal to fetch the darn file descriptor!
    // Please complain to your compiler/libstdc++ vendor...
#if defined(__GLIBCXX__) || defined(__GLIBCPP__)
    // OK, stop reading here, because it's getting obscene.  Cross fingers!
# if defined(__GLIBCXX__)  // >= GCC 3.4.0
    // This applies to cin, cout and cerr when not synced with stdio:
    typedef __gnu_cxx::stdio_filebuf<charT, traits> unix_filebuf_t;
    unix_filebuf_t* fbuf = dynamic_cast<unix_filebuf_t*>(stream.rdbuf());
    if (fbuf != NULL) {
        return fbuf->fd();
    }

    // This applies to filestreams:
    typedef std::basic_filebuf<charT, traits> filebuf_t;
    filebuf_t* bbuf = dynamic_cast<filebuf_t*>(stream.rdbuf());
    if (bbuf != NULL) {
        // This subclass is only there for accessing the FILE*.  Ouuwww, sucks!
        struct my_filebuf : public std::basic_filebuf<charT, traits> {
            int fd() { return this->_M_file.fd(); }
        };
        return static_cast<my_filebuf*>(bbuf)->fd();
    }

    // This applies to cin, cout and cerr when synced with stdio:
    typedef __gnu_cxx::stdio_sync_filebuf<charT, traits> sync_filebuf_t;
    sync_filebuf_t* sbuf = dynamic_cast<sync_filebuf_t*>(stream.rdbuf());
    if (sbuf != NULL) {
#  if (__GLIBCXX__<20040906) // GCC < 3.4.2
        // This subclass is only there for accessing the FILE*.
        // See GCC PR#14600 and PR#16411.
        struct my_filebuf : public sync_filebuf_t {
            my_filebuf();  // Dummy ctor keeps the compiler happy.
            // Note: stdio_sync_filebuf has a FILE* as its first (but private)
            // member variable.  However, it is derived from basic_streambuf<>
            // and the FILE* is the first non-inherited member variable.
            FILE* c_file() {
                return *(FILE**)((char*)this + sizeof(std::basic_streambuf<charT, traits>));
            }
        };
        return ::fileno(static_cast<my_filebuf*>(sbuf)->c_file());
#  else
        return ::fileno(sbuf->file());
#  endif
    }
# else  // GCC < 3.4.0 used __GLIBCPP__
#  if (__GLIBCPP__>=20020514)  // GCC >= 3.1.0
    // This applies to cin, cout and cerr:
    typedef __gnu_cxx::stdio_filebuf<charT, traits> unix_filebuf_t;
    unix_filebuf_t* buf = dynamic_cast<unix_filebuf_t*>(stream.rdbuf());
    if (buf != NULL) {
        return buf->fd();
    }

    // This applies to filestreams:
    typedef std::basic_filebuf<charT, traits> filebuf_t;
    filebuf_t* bbuf = dynamic_cast<filebuf_t*>(stream.rdbuf());
    if (bbuf != NULL) {
        // This subclass is only there for accessing the FILE*.  Ouuwww, sucks!
        struct my_filebuf : public std::basic_filebuf<charT, traits> {
            // Note: _M_file is of type __basic_file<char> which has a
            // FILE* as its first (but private) member variable.
            FILE* c_file() { return *(FILE**)(&this->_M_file); }
        };
        FILE* c_file = static_cast<my_filebuf*>(bbuf)->c_file();
        if (c_file != NULL) {  // Could be NULL for failed ifstreams.
            return ::fileno(c_file);
        }
    }
#  else  // GCC 3.0.x
    typedef std::basic_filebuf<charT, traits> filebuf_t;
    filebuf_t* fbuf = dynamic_cast<filebuf_t*>(stream.rdbuf());
    if (fbuf != NULL) {
        struct my_filebuf : public filebuf_t {
            // Note: basic_filebuf<charT, traits> has a __basic_file<charT>* as
            // its first (but private) member variable.  Since it is derived
            // from basic_streambuf<charT, traits> we can guess its offset.
            // __basic_file<charT> in turn has a FILE* as its first (but
            // private) member variable.  Get it by brute force.  Oh, geez!
            FILE* c_file() {
                std::__basic_file<charT>* ptr_M_file = *(std::__basic_file<charT>**)((char*)this + sizeof(std::basic_streambuf<charT, traits>));
#  if _GLIBCPP_BASIC_FILE_INHERITANCE
                // __basic_file<charT> inherits from __basic_file_base<charT>
                return *(FILE**)((char*)ptr_M_file + sizeof(std::__basic_file_base<charT>));
#  else
                // __basic_file<charT> is base class, but with vptr.
                return *(FILE**)((char*)ptr_M_file + sizeof(void*));
#  endif
            }
        };
        return ::fileno(static_cast<my_filebuf*>(fbuf)->c_file());
    }
#  endif
# endif
#else
    return stream.rdbuf()->fd();  // Maybe a good start?
#endif
    errno = EBADF;
    return -1;
}

//! 8-Bit character instantiation: fileno(ios).
template <>
int
fileno<char>(const std::ios& stream)
{
    return fileno_hack(stream);
}

#if !(defined(__GLIBCXX__) || defined(__GLIBCPP__)) || (defined(_GLIBCPP_USE_WCHAR_T) || defined(_GLIBCXX_USE_WCHAR_T))
//! Wide character instantiation: fileno(wios).
template <>
int
fileno<wchar_t>(const std::wios& stream)
{
    return fileno_hack(stream);
}

Pete

  • Moderator
  • Hero Member
  • *****
  • Posts: 6240
  • Cuz I sez so varmint!
Re: FILEATTR
« Reply #6 on: January 10, 2010, 08:03:51 PM »
I actually had a hunch those two would be "married" in some way. Well hopefully these file procedures will be next on the list for the next-next release. If not, I may end up buying a Power Basic 64-bit console compiler. I figure by March, I'll have computer #2 that is 64/64. Right now, I can't run my network programs on the one I just bought and as I replace my other older systems, I really want to regain the use of my network programs.

Thanks for all your efforts on this qbguy,

Pete
It's only rocket science; it's not Linux!

Johny B.

  • Sr. Member
  • ****
  • Posts: 484
    • Email
Re: FILEATTR
« Reply #7 on: September 21, 2011, 05:58:14 AM »
Technically, this should be implemented for complete combatibility, but unless someone can find a piece of source code that used this function, there doesn't need to be any hurry whatsoever in implementing it. (Maybe put it in as a stub function?)
"Time is an illusion; Lunchtime doubly so." - Douglas Adams

  • Print