Diff for /parser3/src/main/pa_common.C between versions 1.114 and 1.123

version 1.114, 2002/08/05 13:47:37 version 1.123, 2002/11/21 09:18:19
Line 8 Line 8
 static const char* IDENT_COMMON_C="$Date$";  static const char* IDENT_COMMON_C="$Date$";
   
 #include "pa_common.h"  #include "pa_common.h"
 #include "pa_types.h"  
 #include "pa_exception.h"  #include "pa_exception.h"
 #include "pa_pool.h"  
 #include "pa_globals.h"  #include "pa_globals.h"
 #include "pa_value.h"  
 #include "pa_hash.h"  
 #include "pa_string.h"  
   
 #ifdef WIN32  #ifdef WIN32
 #       include <windows.h>  #       include <windows.h>
Line 28  static const char* IDENT_COMMON_C="$Date Line 23  static const char* IDENT_COMMON_C="$Date
 #ifndef _O_BINARY  #ifndef _O_BINARY
 #       define _O_BINARY 0  #       define _O_BINARY 0
 #endif  #endif
 #ifndef O_TRUNC  
 #       define O_TRUNC 0  
 #endif  
   
 // locking constants  // locking constants
   
Line 119  char *file_read_text(Pool& pool, const S Line 111  char *file_read_text(Pool& pool, const S
         void *result;  size_t size;          void *result;  size_t size;
         return file_read(pool, file_spec, result, size, true, fail_on_read_problem)?(char *)result:0;          return file_read(pool, file_spec, result, size, true, fail_on_read_problem)?(char *)result:0;
 }  }
   
   #ifndef DOXYGEN
   struct File_read_action_info {
           void **data; size_t *data_size;
   };
   #endif
   static void file_read_action(Pool& pool,
                                                            int f, 
                                                            const String& file_spec, const char *fname, bool as_text,
                                                            void *context) {
           File_read_action_info& info=*static_cast<File_read_action_info *>(context);
   
       struct stat finfo;
           if(stat(fname, &finfo)!=0)
                   throw Exception("file.missing", // hardly possible: we just opened it OK
                           &file_spec, 
                           "stat failed: %s (%d), actual filename '%s'", 
                                   strerror(errno), errno, fname);
   
           if(size_t to_read_size=(size_t)finfo.st_size) { 
                   *info.data=pool.malloc(to_read_size+(as_text?1:0), 3);
                   *info.data_size=(size_t)read(f, *info.data, to_read_size);
   
                   if(ssize_t(*info.data_size)<0 || *info.data_size>to_read_size)
                           throw Exception(0,
                                   &file_spec, 
                                   "read failed: actually read %lu bytes count not in [0..%lu] valid range", 
                                           *info.data_size, to_read_size);
           } else { // empty file
                   if(as_text) {
                           *info.data=pool.malloc(1);
                           *(char*)(*info.data)=0;
                   } else 
                           *info.data=0;
                   *info.data_size=0;
                   return;
           }
   
           if(as_text) {
                   fix_line_breaks((char *)(*info.data), *info.data_size);
                   // note: after fixing
                   ((char*&)(*info.data))[*info.data_size]=0;
           }
   }
 bool file_read(Pool& pool, const String& file_spec,   bool file_read(Pool& pool, const String& file_spec, 
                            void*& data, size_t& data_size, bool as_text,                             void*& data, size_t& data_size, bool as_text,
                            bool fail_on_read_problem,                             bool fail_on_read_problem) {
                            size_t offset, size_t limit) {          File_read_action_info info={&data, &data_size};
           return file_read_action_under_lock(pool, file_spec, 
                   "read", file_read_action, &info,
                   as_text, fail_on_read_problem);
   }
   
   bool file_read_action_under_lock(Pool& pool, const String& file_spec, 
                                   const char *action_name, File_read_action action, void *context,
                                   bool as_text,
                                   bool fail_on_read_problem) {
         const char *fname=file_spec.cstr(String::UL_FILE_SPEC);          const char *fname=file_spec.cstr(String::UL_FILE_SPEC);
 //printf("file_read(%s)\n", fname);  
         int f;          int f;
     struct stat finfo;  
   
         // first open, next stat:          // first open, next stat:
         // directory update of NTFS hard links performed on open.          // directory update of NTFS hard links performed on open.
Line 136  bool file_read(Pool& pool, const String& Line 179  bool file_read(Pool& pool, const String&
         //   directory entry of b.html in NTFS not updated at once,          //   directory entry of b.html in NTFS not updated at once,
         //   they delay update till open, so we would receive "!^test[" string          //   they delay update till open, so we would receive "!^test[" string
         //   if would do stat, next open.          //   if would do stat, next open.
           // later: it seems, even this does not help sometimes
     if((f=open(fname, O_RDONLY|(as_text?_O_TEXT:_O_BINARY)))>=0) {      if((f=open(fname, O_RDONLY|(as_text?_O_TEXT:_O_BINARY)))>=0) {
                 if(lock_shared_blocking(f)!=0) {                  try {
                         Exception e("file.lock",                          if(lock_shared_blocking(f)!=0)
                                         &file_spec,                                   throw Exception("file.lock",
                                         "shared lock failed: %s (%d), actual filename '%s'",                                                   &file_spec, 
                                                 strerror(errno), errno, fname);                                                  "shared lock failed: %s (%d), actual filename '%s'", 
                         unlock(f);                                                          strerror(errno), errno, fname);
                         close(f);  
                         if(fail_on_read_problem)  
                                 throw e;  
                         return false;  
                 }  
                 if(stat(fname, &finfo)!=0) {  
                         Exception e("file.missing",  
                                         &file_spec,   
                                         "stat failed: %s (%d), actual filename '%s'",   
                                                 strerror(errno), errno, fname);  
                         unlock(f);  
                         close(f);  
                         if(fail_on_read_problem)  
                                 throw e;  
                         return false;  
                 }  
 #ifdef NO_FOREIGN_GROUP_FILES  #ifdef NO_FOREIGN_GROUP_FILES
                 if(finfo.st_gid/*foreign?*/!=getegid()) {                          if(finfo.st_gid/*foreign?*/!=getegid()) {
                         Exception e("parser.runtime",                                  throw Exception("parser.runtime",
                                 &file_spec,                                          &file_spec,
                                 "parser reading files of foreign group disabled [recompile parser without --disable-foreign-group-files configure option], actual filename '%s'",                                           "parser reading files of foreign group disabled [recompile parser without --disable-foreign-group-files configure option], actual filename '%s'", 
                                         fname);                                                  fname);
                         unlock(f);  
                         close(f);  
                         if(fail_on_read_problem)  
                                 throw e;  
                         return false;  
                 }  
 #endif  #endif
                 size_t max_size=limit?min(offset+limit, (size_t)finfo.st_size)-offset:finfo.st_size;  
                 if(!max_size) { // eof  
                         if(as_text) {  
                                 data=pool.malloc(1);  
                                 *(char*)data=0;  
                         } else   
                                 data=0;  
                         data_size=0;  
                 } else {  
                         data=pool.malloc(max_size+(as_text?1:0), 3);  
                         if(offset)  
                                 lseek(f, offset, SEEK_SET);  
                         data_size=read(f, data, max_size);  
                 }  
                 unlock(f);  
                 close(f);  
                 if(!max_size) // eof  
                         return true;  
   
                 if(int(data_size)<0 || data_size>max_size)                          action(pool, f, file_spec, fname, as_text, context);
                         throw Exception(0,                  } catch(...) {
                                 &file_spec,                           unlock(f);close(f);
                                 "read failed: actually read %d bytes count not in [0..%lu] valid range",                           if(fail_on_read_problem)
                                         data_size, (unsigned long)max_size); //never                                  /*re*/throw;
                           return false;                   
                   } 
   
                 if(as_text) {                  unlock(f);close(f);
                         fix_line_breaks((char *)data, data_size);  
                         // note: after fixing  
                         ((char*&)data)[data_size]=0;  
                 }  
                 return true;                  return true;
     }      } else {
         if(fail_on_read_problem)                  if(fail_on_read_problem)
                 throw Exception(errno==EACCES?"file.access":errno==ENOENT?"file.missing":0,                          throw Exception(errno==EACCES?"file.access":errno==ENOENT?"file.missing":0,
                         &file_spec,                                   &file_spec, 
                         "read failed: %s (%d), actual filename '%s'",                                   "%s failed: %s (%d), actual filename '%s'", 
                                 strerror(errno), errno, fname);                                          action_name, strerror(errno), errno, fname);
     return false;                  return false;
           }
 }  }
   
 static void create_dir_for_file(const String& file_spec) {  static void create_dir_for_file(const String& file_spec) {
Line 223  static void create_dir_for_file(const St Line 227  static void create_dir_for_file(const St
   
 bool file_write_action_under_lock(  bool file_write_action_under_lock(
                                 const String& file_spec,                                   const String& file_spec, 
                                 const char *action_name, void (*action)(int, void *), void *context,                                  const char *action_name, File_write_action action, void *context,
                                 bool as_text,                                  bool as_text,
                                 bool do_append,                                  bool do_append,
                                 bool do_block,                                  bool do_block,
Line 236  bool file_write_action_under_lock( Line 240  bool file_write_action_under_lock(
         if((f=open(fname,           if((f=open(fname, 
                 O_CREAT|O_RDWR                  O_CREAT|O_RDWR
                 |(as_text?_O_TEXT:_O_BINARY)                  |(as_text?_O_TEXT:_O_BINARY)
                 |(do_append?O_APPEND:O_TRUNC), 0664))>=0) {                  |(do_append?O_APPEND:0), 0664))>=0) {
                 if((do_block?lock_exclusive_blocking(f):lock_exclusive_nonblocking(f))!=0) {                  if((do_block?lock_exclusive_blocking(f):lock_exclusive_nonblocking(f))!=0) {
                         Exception e("file.lock",                          Exception e("file.lock",
                                 &file_spec,                                   &file_spec, 
Line 251  bool file_write_action_under_lock( Line 255  bool file_write_action_under_lock(
                 try {                  try {
                         action(f, context);                          action(f, context);
                 } catch(...) {                  } catch(...) {
 #if O_TRUNC==0  
                         if(!do_append)                          if(!do_append)
                                 ftruncate(f, tell(f));                                  ftruncate(f, tell(f)); // one can not use O_TRUNC, read lower
 #endif                          unlock(f);close(f);
                         unlock(f);  
                         close(f);  
                         /*re*/throw;                          /*re*/throw;
                 }                  }
                                   
 #if O_TRUNC==0  
                 if(!do_append)                  if(!do_append)
                         ftruncate(f, tell(f));                          ftruncate(f, tell(f)); // O_TRUNC truncates even exclusevely write-locked file [thanks to Igor Milyakov <virtan@rotabanner.com> for discovering]
 #endif                  unlock(f);close(f);
                 unlock(f);  
                 close(f);  
                 return true;                  return true;
         } else          } else
                 throw Exception(errno==EACCES?"file.access":0,                  throw Exception(errno==EACCES?"file.access":0,
Line 283  struct File_write_action_info { Line 281  struct File_write_action_info {
 static void file_write_action(int f, void *context) {  static void file_write_action(int f, void *context) {
         File_write_action_info& info=*static_cast<File_write_action_info *>(context);          File_write_action_info& info=*static_cast<File_write_action_info *>(context);
         if(info.size) {          if(info.size) {
                 size_t written=write(f, info.data, info.size);                  int written=write(f, info.data, info.size);
                 if(written!=info.size)                  if(written<0)
                         throw Exception(0,                          throw Exception(0,
                                 0,                                  0,
                                 "write failed: %s (%d), number of bytes written not equal to requested (%u!=%u)",                                   "write failed: %s (%d)",  strerror(errno), errno);
                                         strerror(errno), errno,  
                                         written, info.size);  
         }          }
 }  }
 void file_write(  void file_write(
Line 343  void file_move(const String& old_spec, c Line 339  void file_move(const String& old_spec, c
 }  }
   
   
   bool entry_exists(const char *fname, struct stat *afinfo) {
           struct stat lfinfo;
           bool result=stat(fname, &lfinfo)==0;
           if(afinfo)
                   *afinfo=lfinfo;
           return result;
   }
   
   bool entry_exists(const String& file_spec) {
           const char *fname=file_spec.cstr(String::UL_FILE_SPEC);
           return entry_exists(fname, 0);
   }
   
 static bool entry_readable(const String& file_spec, bool need_dir) {  static bool entry_readable(const String& file_spec, bool need_dir) {
     const char *fname=file_spec.cstr(String::UL_FILE_SPEC);      char *fname=file_spec.cstr(String::UL_FILE_SPEC);
           if(need_dir) {
                   size_t size=strlen(fname);
                   while(size) {
                           char c=fname[size-1];
                           if(c=='/' || c=='\\')
                                   fname[--size]=0;
                           else
                                   break;
                   }
           }
         struct stat finfo;          struct stat finfo;
         if(access(fname, R_OK)==0 && stat(fname, &finfo)==0) {          if(access(fname, R_OK)==0 && entry_exists(fname, &finfo)) {
                 bool is_dir=(finfo.st_mode&S_IFDIR) != 0;                  bool is_dir=(finfo.st_mode&S_IFDIR) != 0;
                 return is_dir==need_dir;                  return is_dir==need_dir;
         }          }
Line 508  char *unescape_chars(Pool& pool, const c Line 527  char *unescape_chars(Pool& pool, const c
         return s;          return s;
 }  }
   
 /// used by attributed_meaning_to_string / append_attribute_subattribute  
 struct Attributed_meaning_info {  
         String *header; // header line being constructed  
         String::Untaint_lang lang; // language in which to append to that line  
 };  
 static void append_attribute_subattribute(const Hash::Key& akey, Hash::Val *avalue,   
                                                                                   void *info) {  
         if(akey==VALUE_NAME)  
                 return;  
   
         Attributed_meaning_info& ami=*static_cast<Attributed_meaning_info *>(info);  
   
         // ...; charset=windows1251  
         *ami.header << "; ";  
         ami.header->append(akey, ami.lang);  
         *ami.header << "=";  
         ami.header->append(static_cast<Value *>(avalue)->as_string(), ami.lang);  
 }  
 const String& attributed_meaning_to_string(Value& meaning,   
                                                                                    String::Untaint_lang lang) {  
         String &result=*new(meaning.pool()) String(meaning.pool());  
         if(Hash *hash=meaning.get_hash(0)) {  
                 // $value(value) $subattribute(subattribute value)  
                 if(Value *value=static_cast<Value *>(hash->get(*value_name)))  
                         result.append(value->as_string(), lang, true);  
   
                 Attributed_meaning_info attributed_meaning_info={  
                         &result,  
                         lang  
                 };  
                 hash->for_each(append_attribute_subattribute, &attributed_meaning_info);  
         } else // result value  
                 result.append(meaning.as_string(), lang, true);  
   
         return result;  
 }  
   
 #ifdef WIN32  #ifdef WIN32
 void back_slashes_to_slashes(char *s) {  void back_slashes_to_slashes(char *s) {
         if(s)          if(s)

Removed from v.1.114  
changed lines
  Added in v.1.123


E-mail: