Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

miodevice.cc

Go to the documentation of this file.
00001 
00025 #include <sys/types.h>  // For stat()
00026 #include <sys/stat.h>   // For stat()
00027 #include <unistd.h>     // For stat()
00028 #include <fcntl.h>      // For open()
00029 #include <errno.h>
00030 
00031 #include "magic/miodevice.h"
00032 
00033 BEGIN_NAMESPACE (MagiC);
00034 
00036 //                                                                           //
00037 //                 ---  ___  ___               o                             //
00038 //                  |  |   | |  \   ___           ___   ___                  //
00039 //                  |  |   | |   | /   ) |   | | |   \ /   )                 //
00040 //                  |  |   | |   | |---   \ /  | |     |---                  //
00041 //                 _|_ `___´ |__/   \__    V   |  \__/  \__                  //
00042 //                                                                           //
00044 
00045 /*****************************************************************************/
00048 IODevice::IODevice ()
00049 {
00050     mType = 0;
00051     mMode = 0;
00052     mState = 0;
00053     mStatus = 0;
00054 }
00055 
00058 IODevice::~IODevice ()
00059 {
00060 }
00061 
00064 bool IODevice::isDirectAccess () const
00065 {
00066     return false;
00067 }
00068 
00071 bool IODevice::isSequentialAccess () const
00072 {
00073     return false;
00074 }
00075 
00078 bool IODevice::isSynchronous () const
00079 {
00080     return mMode & IO_Raw;
00081 }
00082 
00085 bool IODevice::isAsynchronous () const
00086 {
00087     return !(mMode & IO_Raw);
00088 }
00089 
00112 bool IODevice::open (int mode   )
00113 {
00114     MUST_OVERLOAD;
00115     return false;
00116 }
00117 
00122 void IODevice::close ()
00123 {
00124     MUST_OVERLOAD;
00125 }
00126 
00137 void IODevice::flush ()
00138 {
00139     MUST_OVERLOAD;
00140 }
00141 
00146 uint IODevice::size () const
00147 {
00148     MUST_OVERLOAD;
00149     return 0;
00150 }
00151 
00156 int IODevice::at () const
00157 {
00158     MUST_OVERLOAD;
00159     return 0;
00160 }
00161 
00166 bool IODevice::atEnd () const
00167 {
00168     MUST_OVERLOAD;
00169     return true;
00170 }
00171 
00178 bool IODevice::seek (int position   )
00179 {
00180     return false;
00181 }
00182 
00187 bool IODevice::reset ()
00188 {
00189     return true;
00190 }
00191 
00196 int IODevice::readBlock (char* data,        
00197                          uint maxlen         )
00198     throw (device_not_open)
00199 {
00200     MUST_OVERLOAD;
00201     return 0;
00202 }
00203 
00208 int IODevice::writeBlock (
00209     const char* data,   
00210     uint len)           
00211     throw (device_not_open)
00212 {
00213     MUST_OVERLOAD;
00214     return 0;
00215 }
00216 
00242 int IODevice::readLine (
00243     char* data,         
00244     uint maxlen)        
00245     throw (device_not_open)
00246 {
00247     int pos = 0; // Current position in the data buffer.
00248 
00249     // Read until the maximum length (minus 1 for the terminating zero) is
00250     // reached, or the end of file is reached.
00251     for (pos=0; !atEnd() && pos< int(maxlen)-1; pos++) {
00252         char ch = getch();
00253         data[pos] = ch;
00254         if (ch == '\n')
00255             break;
00256     }
00257     data[pos+1] = '\0'; // Terminate the string properly.
00258 
00259     return 0;
00260 }
00261 
00266 int IODevice::writeBlock (const String& str  )
00267     throw (device_not_open)
00268 {
00269     return writeBlock ((const char*) str, str.length());
00270 }
00271 
00276 Ref<String> IODevice::readAll ()
00277     throw (device_not_open)
00278 {
00279     Ref<String> result = new String ();
00280     char buffer[1024];
00281 
00282     while (!atEnd()) {
00283         int bytesread = readBlock (buffer, 1024);
00284         if (bytesread == 0)
00285             break;
00286         result->append (buffer, bytesread);
00287     }
00288     
00289     return result;
00290 }
00291 
00297 List<String>* IODevice::readLines ()
00298     throw (device_not_open)
00299 {
00300     List<String>* result = new List<String> ();
00301     
00302     return result;
00303 }
00304 
00309 int IODevice::getch ()
00310     throw (device_not_open)
00311 {
00312     MUST_OVERLOAD;
00313     return 0;
00314 }
00315 
00318 void IODevice::putch (char)
00319     throw (device_not_open)
00320 {
00321     MUST_OVERLOAD;
00322 }
00323 
00324 /*****************************************************************************/
00329 void IODevice::ungetch (char)
00330     throw (device_not_open)
00331 {
00332     MUST_OVERLOAD;
00333 }
00334 
00335 
00336 
00338 //                                                                           //
00339 //                              ----- o |                                    //
00340 //                              |       |  ___                               //
00341 //                              |---  | | /   )                              //
00342 //                              |     | | |---                               //
00343 //                              |     | |  \__                               //
00344 //                                                                           //
00346 
00351 File::File (FILE* file )
00352         : IODevice ()
00353 {
00354     mName       = "";
00355     mpFile      = file;
00356     mFd         = fileno (mpFile);
00357 
00358     // We assume that the FILE is already opened.
00359     setOpen ();
00360 }
00361 
00370 File::File (const String& name  ,
00371             int mode            )
00372     throw (open_failure)
00373         : IODevice ()
00374 {
00375     mName   = name;
00376     mpFile  = NULL;
00377     mFd     = 0;
00378 
00379     if (mode) {
00380         // The device must be opened either readable or writable or both
00381         if (! ((mode & IO_Readable) || (mode & IO_Writable)))
00382             throw open_failure (i18n("File '%1' must be opened either readable or writable or both; mode was %2.")
00383                                 .arg(mName).arg(mode));
00384         
00385         // Open the file
00386         if (! open (mode))
00387             throw open_failure (i18n("Opening file '%1' with flags %2 failed for some reason.")
00388                                 .arg(mName).arg(mode));
00389         setOpen ();
00390     }
00391 }
00392 
00398 bool File::exists () const throw (system_failure)
00399 {
00400     struct stat statbuf; // For storing the status information about the file.
00401 
00402     // Get the file status
00403     int result = stat ((CONSTR) mName, &statbuf);
00404 
00405     if (result != 0) {
00406         // File does not exist
00407         if (errno == ENOENT)
00408             return false;
00409 
00410         // Some other error. Can't handle it cleanly.
00411         throw system_failure (i18n("System error '%1' while checking the existence of file '%2'.")
00412                               .arg(strerror(errno)).arg(mName));
00413     }
00414     
00415     return true; // File exists.
00416 }
00417 
00422 bool File::remove ()
00423 {
00424     int result = ::remove ((CONSTR) mName);
00425     if (result != 0)
00426         return true;
00427     else
00428         return false;
00429 }
00430 
00431 /*******************************************************************************
00432  *
00433 **/
00434 bool File::open (int mode)
00435 {
00436     if (isOpen())
00437         close ();
00438 
00439     // Translate mode to flags for the system open function.
00440     String fopenMode = translateToFOpenMode (mode);
00441     if (fopenMode.isEmpty())
00442         return false; // Failed
00443     
00444     // Try to open using the standard C open
00445     FILE* file = fopen ((CONSTR) mName, (CONSTR) fopenMode);
00446 
00447 #ifdef IODEV_USE_EXCEPTIONS
00448     if (!file) {
00449         // Error state, errno has been set
00450         
00451         if (errno == EINVAL)
00452             throw invalid_flags (i18n("Invalid mode flags '%1' for opening file '%2'.")
00453                                  .arg(fopenMode).arg(mName));
00454         if (errno == ENOENT)
00455             throw file_not_found (i18n("File '%2' not found.")
00456                                   .arg(mName));
00457             
00458         throw open_failure (i18n("Error '%1' while trying to open file '%2'.")
00459                             .arg(strerror(errno)).arg(mName));
00460     }
00461 #else
00462     if (!file)
00463         return false; // Failed
00464 #endif
00465 
00466     // Set object state to open
00467     mpFile  = file;
00468     mFd     = fileno (mpFile);
00469     setMode (mode);
00470     setOpen ();
00471 
00472     return true; // Succeeded
00473 }
00474 
00475 /*******************************************************************************
00476  *
00477 **/
00478 void File::close ()
00479 {
00480 #ifdef IODEV_USE_EXCEPTIONS
00481     if (! mpFile)
00482         throw device_not_open (i18n ("File not open when closing file '%1'.").arg(mName));
00483 #else
00484     if (! mpFile)
00485         return;
00486 #endif
00487 
00488     // Close with the system call
00489     fclose (mpFile);
00490 
00491     // Set object state to closed.
00492     mpFile = NULL;
00493     mFd    = 0;
00494     setState (IO_Open, false);
00495 }
00496 
00497 /*******************************************************************************
00498  *
00499 **/
00500 void File::flush ()
00501 {
00502     if (! mpFile)
00503         throw device_not_open (i18n ("File not open when flushing file '%1'.").arg(mName));
00504 
00505     fflush (mpFile);
00506 }
00507 
00510 uint File::size () const
00511 {
00512     struct stat statbuf; // For storing the status information about the file.
00513 
00514     // Get the file status
00515     int callResult = stat ((CONSTR) mName, &statbuf);
00516 
00517     if (!callResult)
00518         throw system_failure (i18n("System error '%1' while checking the size of file '%1'.")
00519                               .arg(strerror(errno)).arg(mName));
00520 
00521     return statbuf.st_size;
00522 }
00523 
00524 /*******************************************************************************
00525  *
00526 **/
00527 int File::at () const
00528 {
00529     if (!isOpen())
00530         throw device_not_open (i18n ("File not open when inquiring the current position in file '%1'.").arg(mName));
00531 
00532     int position = ftell (mpFile);
00533     if (position < 0)
00534         throw system_failure (i18n("System error '%1' while inquiring the current position in file '%1'.")
00535                               .arg(strerror(errno)).arg(mName));
00536 
00537     return position;
00538 }
00539 
00540 /*******************************************************************************
00541  *
00542 **/
00543 bool File::seek (int position)
00544 {
00545     if (!isOpen ())
00546         throw device_not_open (i18n ("File not open when inquiring the current position in file '%1'.").arg(mName));
00547 
00548     int callResult = fseek (mpFile, (long) position, SEEK_SET);
00549 
00550     if (!callResult)
00551         return false;
00552 
00553     return true;
00554 }
00555 
00558 bool File::atEnd () const
00559 {
00560     if (mpFile)
00561         return feof (mpFile);
00562     else
00563         return true;
00564 }
00565 
00572 int File::readBlock (char* data,    
00573                      uint maxlen    )
00574     throw (device_not_open)
00575 {
00576     ASSERT (data && maxlen>0);
00577     if (atEnd())
00578         return 0;
00579 
00580     // TODO: Error handling
00581     int bytesread = fread (data, 1, maxlen, mpFile);
00582 
00583     if (feof(mpFile))
00584         setState (IO_EOS);
00585 
00586     return bytesread;
00587 }
00588 
00589 /*******************************************************************************
00590  *
00591 **/
00592 int File::readLine (char* data,     
00593                     uint maxlen     )
00594     throw (device_not_open)
00595 {
00596     ASSERT (data && maxlen>0);
00597     if (atEnd())
00598         return 0;
00599 
00600     // TODO: Error handling
00601     fgets (data, maxlen, mpFile);
00602 
00603     if (feof(mpFile))
00604         setState (IO_EOS);
00605 
00606     return strlen (data); // Calculate bytes read
00607 }
00608 
00616 int File::readLine (String& buffer, 
00617                     int maxlen      )
00618     throw (device_not_open)
00619 {
00620     if (atEnd())
00621         return 0;
00622 
00623     if (!isOpen())
00624         throw device_not_open (i18n ("File not open when reading a line from file '%1'.").arg(mName));
00625 
00626     // TODO: Error handling
00627     int bytesread = fgetS (mpFile, buffer);
00628 
00629     if (feof(mpFile))
00630         setState (IO_EOS);
00631 
00632     return bytesread;
00633 }
00634 
00639 int File::writeBlock (const char* data, 
00640                       uint len          )
00641     throw (device_not_open)
00642 {
00643     if (!isOpen())
00644         throw device_not_open (i18n ("File not open when writing to file '%1'.").arg(mName));
00645 
00646     // TODO: Error handling
00647     int result = fwrite (data, 1, len, mpFile);
00648 
00649     return result;
00650 }
00651 
00652 /*******************************************************************************
00653  *
00654 **/
00655 int File::getch ()
00656     throw (device_not_open)
00657 {
00658     if (!isOpen())
00659         throw device_not_open (i18n ("File not open when reading a from file '%1'.").arg(mName));
00660 
00661     // TODO: Error handling
00662     int result = ::fgetc(mpFile);
00663     
00664     if (result == EOF) {
00665         setState (IO_EOS);
00666         result = 0;
00667         return (-1);
00668     }
00669     
00670     return result;
00671 }
00672 
00673 /*******************************************************************************
00674  *
00675 **/
00676 void File::putch (char ch)
00677     throw (device_not_open)
00678 {
00679     if (!isOpen())
00680         throw device_not_open (i18n ("File not open when writing to file '%1'.").arg(mName));
00681 
00682     // int status = 
00683     fputc (ch, mpFile);
00684     // TODO: Error handling
00685 }
00686 
00692 void File::ungetch (char ch)
00693     throw (device_not_open)
00694 {
00695     if (!isOpen())
00696         throw device_not_open (i18n ("File not open when ungetting from file '%1'.").arg(mName));
00697     
00698     // If at EOS, return to open state.
00699     if (state() & IO_EOS)
00700         setState (IO_EOS, false);
00701 
00702     // int status = 
00703     ungetc (ch, mpFile);
00704     // TODO: Error handling
00705 }
00706 
00707 /*******************************************************************************
00708  *
00709 **/
00710 int File::handle ()
00711 {
00712     return mFd;
00713 }
00714 
00717 String File::translateToFOpenMode (int mode ) throw (invalid_flags)
00718 {
00719     if (mode & IO_Readable)
00720         if (mode & IO_Writable)
00721             if (mode & IO_Append)
00722                 return "a+";            // Open for RW, do not truncate, position at EOF
00723             else
00724                 if (mode & IO_Truncate)
00725                     return "w+";        // Open for RW, truncate, position at BOF
00726                 else
00727                     return "r+";        // Open for RW, do not truncate, position at BOF
00728         else
00729             return "r";                 // Open for R, position at BOF
00730     else
00731         if (mode & IO_Writable)
00732             if (mode & IO_Append)
00733                 return "a";             // Open for W, do not truncate, position at EOF
00734             else
00735                 return "w";             // Open for W, truncate, position at BOF
00736 
00737     return ""; // This would actually be an error state.
00738 }
00739 
00742 int File::translateToOpenMode (int mode ) throw (invalid_flags)
00743 {
00744     int sysmode = 0;
00745     if (mode & IO_Readable)
00746         if (mode & IO_Writable)
00747             sysmode |= O_RDWR;
00748         else
00749             sysmode |= O_RDONLY;
00750     else
00751         if (mode & IO_Writable)
00752             sysmode |= O_WRONLY;
00753         else
00754             return false; // Failed
00755 
00756     if (mode & IO_Append)
00757         sysmode |= O_APPEND;
00758 
00759     if (mode & IO_Truncate)
00760         sysmode |= O_TRUNC;
00761 
00762     return sysmode;
00763 }
00764 
00765 
00766 
00768 //                                                                           //
00769 //                       ----                                                //
00770 //                       |   )        __  __  ___                            //
00771 //                       |---  |   | /   /   /   ) |/\                       //
00772 //                       |   ) |   | +-- +-- |---  |                         //
00773 //                       |___   \__! |   |    \__  |                         //
00774 //                                   |   |                                   //
00776 
00779 Buffer::Buffer (int mode)
00780 {
00781     mpBuffer    = new String();
00782     mPosition   = 0;
00783     mOwnBuffer  = true;
00784 
00785     // Try to open, if mode was given
00786     if (mode)
00787         if (! open (mode))
00788             throw open_failure (i18n("Opening Buffer device with flags %1 failed for some reason.")
00789                                 .arg(mode));
00790 }
00791 
00796 Buffer::Buffer (String& buffer, int mode)
00797 {
00798     mpBuffer    = &buffer;
00799     mPosition   = 0;
00800     mOwnBuffer  = false;
00801 
00802     // Try to open, if mode was given
00803     if (mode)
00804         if (! open (mode))
00805             throw open_failure (i18n("Opening Buffer device with flags %1 failed for some reason.")
00806                                 .arg(mode));
00807 }
00808 
00809 Buffer::~Buffer ()
00810 {
00811     if (mOwnBuffer)
00812         delete mpBuffer;
00813 }
00814 
00815 bool Buffer::open (int mode)
00816 {
00817     setMode (mode);
00818     setOpen ();
00819 
00820     // This basicly resets position, etc.
00821     reset ();
00822 
00823     if (mode & IO_Truncate)
00824         mpBuffer->empty ();
00825 
00826     if (mode & IO_Append)
00827         mPosition = mpBuffer->length ();
00828 
00829     return true;
00830 }
00831 
00832 bool Buffer::reset ()
00833 {
00834     if (!IODevice::reset ())
00835         return false;
00836 
00837     mPosition = 0;
00838     return true;
00839 }
00840 
00841 bool Buffer::atEnd () const
00842 {
00843     if ((uint) mPosition >= size())
00844         return true;
00845     else
00846         return false;
00847 }
00848 
00849 int Buffer::readBlock (char* data, uint maxlen)
00850     throw (device_not_open)
00851 {
00852     if ((uint) mPosition >= size())
00853         return 0;
00854 
00855     int remains = mpBuffer->length() - mPosition;           // How far is the end of buffer
00856     int readcount = ((uint) remains > maxlen)? maxlen : remains;    // How many bytes will actually be read
00857 
00858     memcpy (data, ((const char*) *mpBuffer) + mPosition, readcount);
00859 
00860     mPosition += readcount;
00861     return readcount;
00862 }
00863 
00864 int Buffer::writeBlock (const char* data, uint len)
00865     throw (device_not_open)
00866 {
00867     mpBuffer->replace (mPosition, data, len); 
00868     mPosition += len;
00869     return len;
00870 }
00871 
00872 int Buffer::readLine (char* data, uint maxlen)
00873     throw (device_not_open)
00874 {
00875     if ((uint) mPosition >= size())
00876         return 0;
00877 
00878     int  remains    = mpBuffer->length() - mPosition;               // How far is the end of buffer
00879     int  maxread    = ((uint) remains > maxlen)? maxlen : remains;  // How many bytes can actually be read
00880     uint newlinePos = mPosition;
00881 
00882     // Find the next newline
00883     for (uint i=0; i < (uint) maxread; i++)
00884         if ((*mpBuffer)[newlinePos++] == '\n')
00885             break;
00886 
00887     // How much was actually read
00888     int readcount = newlinePos - mPosition;
00889 
00890     // Copy everything up to the newline to the result buffer.
00891     memcpy (data, ((const char*) *mpBuffer) + mPosition, newlinePos-mPosition);
00892     data[readcount] = '\x00';
00893 
00894     // Move position pointer to new position
00895     mPosition = newlinePos;
00896 
00897     return readcount;
00898 }
00899 
00900 int Buffer::writeBlock (const String& str)
00901     throw (device_not_open)
00902 {
00903     mpBuffer->append (str);
00904     return str.length();
00905 }
00906 
00907 int Buffer::getch ()
00908     throw (device_not_open)
00909 {
00910     if ((uint) mPosition >= size())
00911         return -1; // EOS
00912 
00913     // TODO: Should we increment?
00914     return (*mpBuffer)[uint(mPosition)];
00915 }
00916 
00917 void Buffer::putch (char c)
00918     throw (device_not_open)
00919 {
00920     // Use reserved buffer if possible, otherwise append (grow the
00921     // buffer).
00922     if ((uint) mPosition >= size()) {
00923         // No room in buffer, append.
00924         mpBuffer->append (c);
00925         mPosition++;
00926     } else
00927         (*mpBuffer)[uint(mPosition++)] = c;
00928 }
00929 
00930 void Buffer::ungetch (char c)
00931     throw (device_not_open)
00932 {
00933     if (mPosition==0)
00934         return;
00935 
00936     // Go back one character, and put the character there.
00937     (mpBuffer)[--mPosition] = c;
00938 }
00939 
00940 END_NAMESPACE;
00941 

Generated on Thu Feb 10 20:06:41 2005 for LibMagiC by doxygen1.2.18