Back to index

lightning-sunbird  0.9+nobinonly
GUSIDevice.h
Go to the documentation of this file.
00001 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
00002 // % Project  :      GUSI                        -      Grand Unified Socket Interface                    
00003 // % File            :      GUSIDevice.nw        -      Devices                                      
00004 // % Author   :      Matthias Neeracher                                           
00005 // % Language :      C++                                                        
00006 // %                                                                       
00007 // % $Log: GUSIDevice.h,v $
00008 // % Revision 1.1  2001/03/11 22:34:48  sgehani%netscape.com
00009 // % First Checked In.
00010 // %                                               
00011 // % Revision 1.13  2000/06/12 04:22:30  neeri                             
00012 // % Return values, not references                                         
00013 // %                                                                       
00014 // % Revision 1.12  2000/05/23 06:58:03  neeri                             
00015 // % Improve formatting                                                    
00016 // %                                                                       
00017 // % Revision 1.11  2000/03/15 07:22:06  neeri                             
00018 // % Enforce alignment choices                                             
00019 // %                                                                       
00020 // % Revision 1.10  2000/03/06 06:30:30  neeri                             
00021 // % Check for nonexistent device                                          
00022 // %                                                                       
00023 // % Revision 1.9  1999/08/26 05:45:01  neeri                              
00024 // % Fixes for literate edition of source code                             
00025 // %                                                                       
00026 // % Revision 1.8  1999/07/19 06:21:02  neeri                              
00027 // % Add mkdir/rmdir, fix various file manager related bugs                
00028 // %                                                                       
00029 // % Revision 1.7  1999/05/29 06:26:42  neeri                              
00030 // % Fixed header guards                                                   
00031 // %                                                                       
00032 // % Revision 1.6  1999/03/17 09:05:07  neeri                              
00033 // % Added GUSITimer, expanded docs                                        
00034 // %                                                                       
00035 // % Revision 1.5  1998/11/22 23:06:52  neeri                              
00036 // % Releasing 2.0a4 in a hurry                                            
00037 // %                                                                       
00038 // % Revision 1.4  1998/10/25 11:37:38  neeri                              
00039 // % More configuration hooks                                              
00040 // %                                                                       
00041 // % Revision 1.3  1998/10/11 16:45:13  neeri                              
00042 // % Ready to release 2.0a2                                                
00043 // %                                                                       
00044 // % Revision 1.2  1998/08/01 21:28:57  neeri                              
00045 // % Add directory operations                                              
00046 // %                                                                       
00047 // % Revision 1.1  1998/01/25 21:02:45  neeri                              
00048 // % Engine implemented, except for signals & scheduling                   
00049 // %                                                                       
00050 // % Revision 1.1  1996/12/16 02:12:40  neeri                              
00051 // % TCP Sockets sort of work                                              
00052 // %                                                                       
00053 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
00054 //                                                                         
00055 // \chapter{Devices}                                                       
00056 //                                                                         
00057 // Similar to the creation of sockets, operations on files like opening or 
00058 // renaming them need to be dispatched to a variety of special cases (Most of
00059 // them of the form "Dev:" preceded by a device name). Analogous to the    
00060 // [[GUSISocketFactory]] subclasses registered in a [[GUSISocketDomainRegistry]],
00061 // we therefore have subclasses of [[GUSIDevice]] registered in a          
00062 // [[GUSIDeviceRegistry]], although the details of the two registries are  
00063 // quite different.                                                        
00064 //                                                                         
00065 // During resolution of a file name, the name and information about it is passed
00066 // around in a [[GUSIFileToken]].                                          
00067 //                                                                         
00068 // <GUSIDevice.h>=                                                         
00069 #ifndef _GUSIDevice_
00070 #define _GUSIDevice_
00071 
00072 #ifdef GUSI_SOURCE
00073 
00074 #include "GUSISocket.h"
00075 #include "GUSIFileSpec.h"
00076 
00077 #include <dirent.h>
00078 #include <utime.h>
00079 
00080 #include <ConditionalMacros.h>
00081 
00082 #if PRAGMA_STRUCT_ALIGN
00083 #pragma options align=native
00084 #endif
00085 
00086 // \section{Definition of [[GUSIFileToken]]}                               
00087 //                                                                         
00088 // A [[GUSIFileToken]] consists of a pointer to the name as a C string, of a pointer
00089 // to the [[GUSIDevice]] the token resolves to, and, if the token refers to a
00090 // file name rather than a device name, a pointer to a [[GUSIFileSpec]]. Since 
00091 // depending on the call, different [[GUSIDevice]] subclasses may handle it, a
00092 // request code has to be passed to the constructor, too.                  
00093 //                                                                         
00094 // <Definition of class [[GUSIFileToken]]>=                                
00095 class GUSIDevice;
00096 
00097 class GUSIFileToken : public GUSIFileSpec {
00098 public:
00099        enum Request {
00100               // \section{Operations on Devices}                                         
00101   //                                                                         
00102   // The [[open]] operation creates a new socket for the specified path or file
00103   // specification.                                                          
00104   //                                                                         
00105   // <Requests for [[GUSIFileToken]]>=                                       
00106   kWillOpen,
00107   // [[remove]] deletes a path or file specification.                        
00108   //                                                                         
00109   // <Requests for [[GUSIFileToken]]>=                                       
00110   kWillRemove,
00111   // [[rename]] renames a path or file specification.                        
00112   //                                                                         
00113   // <Requests for [[GUSIFileToken]]>=                                       
00114   kWillRename,
00115   // [[stat]] gathers statistical data about a file or directory.            
00116   //                                                                         
00117   // <Requests for [[GUSIFileToken]]>=                                       
00118   kWillStat,
00119   // [[chmod]] changes file modes, to the extent that this is meaningful on MacOS.
00120   //                                                                         
00121   // <Requests for [[GUSIFileToken]]>=                                       
00122   kWillChmod,
00123   // [[utime]] bumps a file's modification time.                             
00124   //                                                                         
00125   // <Requests for [[GUSIFileToken]]>=                                       
00126   kWillUtime,
00127   // [[access]] checks access permissions for a file.                        
00128   //                                                                         
00129   // <Requests for [[GUSIFileToken]]>=                                       
00130   kWillAccess,
00131   // [[mkdir]] creates a directory.                                          
00132   //                                                                         
00133   // <Requests for [[GUSIFileToken]]>=                                       
00134   kWillMkdir,
00135   // [[rmdir]] deletes a directory.                                          
00136   //                                                                         
00137   // <Requests for [[GUSIFileToken]]>=                                       
00138   kWillRmdir,
00139   // [[opendir]] opens a directory handle on the given directory.            
00140   //                                                                         
00141   // <Requests for [[GUSIFileToken]]>=                                       
00142   kWillOpendir,
00143   // [[symlink]] creates a symbolic link to a file.                          
00144   //                                                                         
00145   // <Requests for [[GUSIFileToken]]>=                                       
00146   kWillSymlink,
00147   // [[readlink]] reads the contents of a symbolic link.                     
00148   //                                                                         
00149   // <Requests for [[GUSIFileToken]]>=                                       
00150   kWillReadlink,
00151   // [[fgetfileinfo]] and [[fsetfileinfo]] reads and set the type and creator
00152   // code of a file.                                                         
00153   //                                                                         
00154   // <Requests for [[GUSIFileToken]]>=                                       
00155   kWillGetfileinfo,
00156   kWillSetfileinfo,
00157   // [[faccess]] manipulates MPW properties of files.                        
00158   //                                                                         
00159   // <Requests for [[GUSIFileToken]]>=                                       
00160   kWillFaccess,
00161               kNoRequest
00162        };
00163        
00164        GUSIFileToken(const char * path, Request request, bool useAlias = false);
00165        GUSIFileToken(const GUSIFileSpec & spec, Request request);
00166        GUSIFileToken(short fRefNum, Request request);
00167        
00168        bool                 IsFile()             const { return fIsFile;            }
00169        bool                 IsDevice()           const { return !fIsFile;           }
00170        Request                     WhichRequest()       const { return fRequest;           }      
00171        GUSIDevice *  Device()             const {       return fDevice;                    }
00172        const char *  Path()               const { return fPath;                     }
00173        
00174        static bool          StrFragEqual(const char * name, const char * frag);
00175        enum StdStream {
00176               kStdin,
00177               kStdout,
00178               kStderr,
00179               kConsole,
00180               kNoStdStream = -2
00181        };                          
00182        static StdStream StrStdStream(const char * name);
00183        
00184 private:
00185        GUSIDevice *  fDevice;
00186        const char *  fPath;
00187        bool                 fIsFile;
00188        Request                     fRequest;
00189 };
00190 // \section{Definition of [[GUSIDirectory]]}                               
00191 //                                                                         
00192 // [[GUSIDirectory]] is a directory handle to iterate over all entries in a 
00193 // directory.                                                              
00194 //                                                                         
00195 // <Definition of class [[GUSIDirectory]]>=                                
00196 class GUSIDirectory {
00197 public:
00198        virtual                     ~GUSIDirectory() {}
00199        virtual dirent    *  readdir() = 0;
00200        virtual long         telldir() = 0;
00201        virtual void         seekdir(long pos) = 0;
00202        virtual void         rewinddir() = 0;
00203 protected:
00204        friend class GUSIDevice;
00205        GUSIDirectory()     {}
00206 };
00207 // \section{Definition of [[GUSIDeviceRegistry]]}                          
00208 //                                                                         
00209 // The [[GUSIDeviceRegistry]] is a singleton class registering all socket  
00210 // domains.                                                                
00211 //                                                                         
00212 // <Definition of class [[GUSIDeviceRegistry]]>=                           
00213 class GUSIDeviceRegistry {
00214 public:
00215        // The only instance of [[GUSIDeviceRegistry]] is, as usual, obtained by calling
00216  // [[Instance]].                                                           
00217  //                                                                         
00218  // <Creation of [[GUSIDeviceRegistry]]>=                                   
00219  static  GUSIDeviceRegistry *      Instance();
00220        // <Operations for [[GUSIDeviceRegistry]]>=                                
00221  GUSISocket * open(const char * path, int flags);
00222  // <Operations for [[GUSIDeviceRegistry]]>=                                
00223  int remove(const char * path);
00224  // <Operations for [[GUSIDeviceRegistry]]>=                                
00225  int rename(const char * oldname, const char * newname);
00226  // <Operations for [[GUSIDeviceRegistry]]>=                                
00227  int stat(const char * path, struct stat * buf, bool useAlias);
00228  // <Operations for [[GUSIDeviceRegistry]]>=                                
00229  int chmod(const char * path, mode_t mode);
00230  // <Operations for [[GUSIDeviceRegistry]]>=                                
00231  int utime(const char * path, const utimbuf * times);
00232  // <Operations for [[GUSIDeviceRegistry]]>=                                
00233  int access(const char * path, int mode);
00234  // <Operations for [[GUSIDeviceRegistry]]>=                                
00235  int mkdir(const char * path);
00236  // <Operations for [[GUSIDeviceRegistry]]>=                                
00237  int rmdir(const char * path);
00238  // <Operations for [[GUSIDeviceRegistry]]>=                                
00239  GUSIDirectory * opendir(const char * path);
00240  // <Operations for [[GUSIDeviceRegistry]]>=                                
00241  int symlink(const char * target, const char * newlink);
00242  // <Operations for [[GUSIDeviceRegistry]]>=                                
00243  int readlink(const char * path, char * buf, int bufsize);
00244  // <Operations for [[GUSIDeviceRegistry]]>=                                
00245  int fgetfileinfo(const char * path, OSType * creator, OSType * type);
00246  int fsetfileinfo(const char * path, OSType creator, OSType type);
00247  // <Operations for [[GUSIDeviceRegistry]]>=                                
00248  int faccess(const char * path, unsigned * cmd, void * arg);
00249        // [[AddDevice]] and [[RemoveDevice]] add and remove a [[GUSIDevice]].     
00250  //                                                                         
00251  // <Registration interface of [[GUSIDeviceRegistry]]>=                     
00252  void AddDevice(GUSIDevice * device);
00253  void RemoveDevice(GUSIDevice * device);
00254        // It is convenient to define iterators to iterate across all devices.     
00255  //                                                                         
00256  // <Iterator on [[GUSIDeviceRegistry]]>=                                   
00257  class iterator;
00258 
00259  iterator begin();
00260  iterator end();
00261 protected:
00262        // On construction, a [[GUSIFileToken]] looks up the appropriate device in the
00263  // [[GUSIDeviceRegistry]].                                                 
00264  //                                                                         
00265  // <Looking up a device in the [[GUSIDeviceRegistry]]>=                    
00266  friend class GUSIFileToken;
00267 
00268  GUSIDevice * Lookup(GUSIFileToken & file);
00269 private:
00270        // <Privatissima of [[GUSIDeviceRegistry]]>=                               
00271  static GUSIDeviceRegistry *       sInstance;
00272  // Devices are stored in a linked list. On creation of the registry, it immediately
00273  // registers the instance for plain Macintosh file sockets, to which pretty much all
00274  // operations default. This device will never refuse any request.          
00275  //                                                                         
00276  // <Privatissima of [[GUSIDeviceRegistry]]>=                               
00277  GUSIDevice * fFirstDevice;
00278  GUSIDeviceRegistry();
00279 };
00280 // \section{Definition of [[GUSIDevice]]}                                  
00281 //                                                                         
00282 // [[GUSIDevice]] consists of a few maintenance functions and the          
00283 // device operations. The request dispatcher first calls [[Want]] for      
00284 // each candidate device and as soon as it's successful, calls the specific
00285 // operation. Devices are kept in a linked list by the [[GUSIDeviceRegistry]].
00286 //                                                                         
00287 // <Definition of class [[GUSIDevice]]>=                                   
00288 class GUSIDevice {
00289 public:
00290        virtual bool  Want(GUSIFileToken & file);
00291        
00292        // <Operations for [[GUSIDevice]]>=                                        
00293  virtual GUSISocket * open(GUSIFileToken & file, int flags);
00294  // <Operations for [[GUSIDevice]]>=                                        
00295  virtual int remove(GUSIFileToken & file);
00296  // <Operations for [[GUSIDevice]]>=                                        
00297  virtual int rename(GUSIFileToken & from, const char * newname);
00298  // <Operations for [[GUSIDevice]]>=                                        
00299  virtual int stat(GUSIFileToken & file, struct stat * buf);
00300  // <Operations for [[GUSIDevice]]>=                                        
00301  virtual int chmod(GUSIFileToken & file, mode_t mode);
00302  // <Operations for [[GUSIDevice]]>=                                        
00303  virtual int utime(GUSIFileToken & file, const utimbuf * times);
00304  // <Operations for [[GUSIDevice]]>=                                        
00305  virtual int access(GUSIFileToken & file, int mode);
00306  // <Operations for [[GUSIDevice]]>=                                        
00307  virtual int mkdir(GUSIFileToken & file);
00308  // <Operations for [[GUSIDevice]]>=                                        
00309  virtual int rmdir(GUSIFileToken & file);
00310  // <Operations for [[GUSIDevice]]>=                                        
00311  virtual GUSIDirectory * opendir(GUSIFileToken & file);
00312  // <Operations for [[GUSIDevice]]>=                                        
00313  virtual int symlink(GUSIFileToken & to, const char * newlink);
00314  // <Operations for [[GUSIDevice]]>=                                        
00315  virtual int readlink(GUSIFileToken & link, char * buf, int bufsize);
00316  // <Operations for [[GUSIDevice]]>=                                        
00317  virtual int fgetfileinfo(GUSIFileToken & file, OSType * creator, OSType * type);
00318  virtual int fsetfileinfo(GUSIFileToken & file, OSType creator, OSType type);
00319  // <Operations for [[GUSIDevice]]>=                                        
00320  virtual int faccess(GUSIFileToken & file, unsigned * cmd, void * arg);
00321 protected:
00322        friend class GUSIDeviceRegistry;
00323        friend class GUSIDeviceRegistry::iterator;
00324        
00325        GUSIDevice() : fNextDevice(nil)                  {}
00326        virtual ~GUSIDevice()                                   {}
00327        
00328        GUSIDevice    *      fNextDevice;
00329 };
00330 
00331 #if PRAGMA_STRUCT_ALIGN
00332 #pragma options align=reset
00333 #endif
00334 
00335 // \section{Implementation of [[GUSIDeviceRegistry]]}                      
00336 //                                                                         
00337 //                                                                         
00338 // <Definition of [[GUSISetupDevices]] hook>=                              
00339 extern "C" void GUSISetupDevices();
00340 
00341 // <Inline member functions for class [[GUSIDeviceRegistry]]>=             
00342 inline GUSIDeviceRegistry * GUSIDeviceRegistry::Instance()
00343 {
00344        if (!sInstance) {
00345               sInstance = new GUSIDeviceRegistry();
00346               GUSISetupDevices();
00347        }
00348        
00349        return sInstance;
00350 }
00351 // The [[GUSIDeviceRegistry]] forward iterator is simple.                  
00352 //                                                                         
00353 // <Inline member functions for class [[GUSIDeviceRegistry]]>=             
00354 class GUSIDeviceRegistry::iterator {
00355 public:
00356        iterator(GUSIDevice * device = 0) : fDevice(device) {}
00357        GUSIDeviceRegistry::iterator & operator++()             
00358               { fDevice = fDevice->fNextDevice; return *this;                              }
00359        GUSIDeviceRegistry::iterator operator++(int)
00360               { GUSIDeviceRegistry::iterator old(*this); fDevice = fDevice->fNextDevice; return old;     }
00361        bool operator==(const GUSIDeviceRegistry::iterator other) const
00362                                                         { return fDevice==other.fDevice;                 }
00363        GUSIDevice & operator*()    { return *fDevice;                                             }
00364        GUSIDevice * operator->()   { return fDevice;                                              }
00365 private:
00366        GUSIDevice *                       fDevice;
00367 };
00368 
00369 inline GUSIDeviceRegistry::iterator GUSIDeviceRegistry::begin()              
00370 { 
00371        return GUSIDeviceRegistry::iterator(fFirstDevice);      
00372 }
00373 
00374 inline GUSIDeviceRegistry::iterator GUSIDeviceRegistry::end()         
00375 { 
00376        return GUSIDeviceRegistry::iterator();                         
00377 }
00378 
00379 #endif /* GUSI_SOURCE */
00380 
00381 #endif /* _GUSIDevice_ */