|
|
| version 1.107, 2002/03/28 11:50:14 | version 1.119, 2002/09/18 12:40:38 |
|---|---|
| Line 3 | Line 3 |
| Copyright(c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com) | Copyright(c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com) |
| Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) | Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) |
| $Id$ | |
| */ | */ |
| 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 124 bool file_read(Pool& pool, const String& | Line 119 bool file_read(Pool& pool, const String& |
| bool fail_on_read_problem, | bool fail_on_read_problem, |
| size_t offset, size_t limit) { | size_t offset, size_t limit) { |
| 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; | struct stat finfo; |
| Line 137 bool file_read(Pool& pool, const String& | Line 131 bool file_read(Pool& pool, const String& |
| // 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. |
| 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) { |
| lock_shared_blocking(f); | if(lock_shared_blocking(f)!=0) { |
| Exception e("file.lock", | |
| &file_spec, | |
| "shared lock failed: %s (%d), actual filename '%s'", | |
| strerror(errno), errno, fname); | |
| unlock(f); | |
| close(f); | |
| if(fail_on_read_problem) | |
| throw e; | |
| return false; | |
| } | |
| if(stat(fname, &finfo)!=0) { | if(stat(fname, &finfo)!=0) { |
| Exception e("file.missing", | Exception e("file.missing", |
| &file_spec, | &file_spec, |
| Line 193 bool file_read(Pool& pool, const String& | Line 197 bool file_read(Pool& pool, const String& |
| ((char*&)data)[data_size]=0; | ((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'", | "read failed: %s (%d), actual filename '%s'", |
| strerror(errno), errno, fname); | 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 216 bool file_write_action_under_lock( | Line 221 bool file_write_action_under_lock( |
| const char *action_name, void (*action)(int, void *), void *context, | const char *action_name, void (*action)(int, void *), void *context, |
| bool as_text, | bool as_text, |
| bool do_append, | bool do_append, |
| bool do_block) { | bool do_block, |
| bool fail_on_lock_problem) { | |
| const char *fname=file_spec.cstr(String::UL_FILE_SPEC); | const char *fname=file_spec.cstr(String::UL_FILE_SPEC); |
| int f; | int f; |
| if(access(fname, W_OK)!=0) // no | if(access(fname, W_OK)!=0) // no |
| Line 227 bool file_write_action_under_lock( | Line 233 bool file_write_action_under_lock( |
| |(as_text?_O_TEXT:_O_BINARY) | |(as_text?_O_TEXT:_O_BINARY) |
| |(do_append?O_APPEND:O_TRUNC), 0664))>=0) { | |(do_append?O_APPEND:O_TRUNC), 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", | |
| &file_spec, | |
| "shared lock failed: %s (%d), actual filename '%s'", | |
| strerror(errno), errno, fname); | |
| close(f); | close(f); |
| if(fail_on_lock_problem) | |
| throw e; | |
| return false; | return false; |
| } | } |
| Line 265 struct File_write_action_info { | Line 277 struct File_write_action_info { |
| #endif | #endif |
| 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) { |
| write(f, info.data, info.size); | int written=write(f, info.data, info.size); |
| if(written<0) | |
| throw Exception(0, | |
| 0, | |
| "write failed: %s (%d)", strerror(errno), errno); | |
| } | |
| } | } |
| void file_write( | void file_write( |
| const String& file_spec, | const String& file_spec, |
| Line 319 void file_move(const String& old_spec, c | Line 336 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); | const char *fname=file_spec.cstr(String::UL_FILE_SPEC); |
| 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; |
| } | } |
| return false; | return false; |
| Line 411 char *rsplit(char *string, char delim) { | Line 441 char *rsplit(char *string, char delim) { |
| /// @todo less stupid type detection | /// @todo less stupid type detection |
| char *format(Pool& pool, double value, char *fmt) { | char *format(Pool& pool, double value, char *fmt) { |
| char *result=(char *)pool.malloc(MAX_NUMBER, 4); | char local_buf[MAX_NUMBER]; |
| size_t size; | |
| if(fmt) | if(fmt) |
| if(strpbrk(fmt, "diouxX")) | if(strpbrk(fmt, "diouxX")) |
| if(strpbrk(fmt, "ouxX")) | if(strpbrk(fmt, "ouxX")) |
| snprintf(result, MAX_NUMBER, fmt, (uint)value ); | size=snprintf(local_buf, sizeof(local_buf), fmt, (uint)value); |
| else | else |
| snprintf(result, MAX_NUMBER, fmt, (int)value ); | size=snprintf(local_buf, sizeof(local_buf), fmt, (int)value); |
| else | else |
| snprintf(result, MAX_NUMBER, fmt, value); | size=snprintf(local_buf, sizeof(local_buf), fmt, value); |
| else | else |
| snprintf(result, MAX_NUMBER, "%d", (int)value); | size=snprintf(local_buf, sizeof(local_buf), "%d", (int)value); |
| return result; | char *pool_buf=(char *)pool.malloc(size+1, 4); |
| memcpy(pool_buf, local_buf, size+1); | |
| return pool_buf; | |
| } | } |
| size_t stdout_write(const void *buf, size_t size) { | size_t stdout_write(const void *buf, size_t size) { |
| Line 480 char *unescape_chars(Pool& pool, const c | Line 514 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) |