ebc9881999-05-06Henrik Grubbström (Grubba) /*
c9dd7f2000-11-21Per Hedbor  * $Id: Roxen.pmod,v 1.51 2000/11/21 13:17:29 per Exp $
ebc9881999-05-06Henrik Grubbström (Grubba)  * * Various helper functions. * * Henrik Grubbström 1999-05-03 */
69e4cd2000-03-09Martin Stjernholm #include <config.h>
88bff12000-09-12Per Hedbor #include <version.h>
3c4c6e2000-11-02Per Hedbor #include <module.h>
69e4cd2000-03-09Martin Stjernholm inherit "roxenlib";
796fb62000-08-12Per Hedbor // Low-level C-roxen optimization functions. #if constant( _Roxen ) inherit _Roxen; #endif
ebc9881999-05-06Henrik Grubbström (Grubba) /* * TODO: * * o Quota: Fix support for the index file. * */ #ifdef QUOTA_DEBUG #define QD_WRITE(X) werror(X) #else /* !QUOTA_DEBUG */ #define QD_WRITE(X) #endif /* QUOTA_DEBUG */
7e9a0b2000-09-16Per Hedbor #undef CACHE #undef NOCACHE #define CACHE(id,X) ([mapping(string:mixed)]id->misc)->cacheable=min(([mapping(string:mixed)]id->misc)->cacheable,X) #define NOCACHE(id) ([mapping(string:mixed)]id->misc)->cacheable=0
ebc9881999-05-06Henrik Grubbström (Grubba) class QuotaDB { #if constant(create_thread) object(Thread.Mutex) lock = Thread.Mutex();
2543b72000-07-02Henrik Grubbström (Grubba) #define LOCK() mixed key__; catch { key__ = lock->lock(); }
ebc9881999-05-06Henrik Grubbström (Grubba) #define UNLOCK() do { if (key__) destruct(key__); } while(0) #else /* !constant(create_thread) */ #define LOCK() #define UNLOCK() #endif /* constant(create_thread) */ constant READ_BUF_SIZE = 256; constant CACHE_SIZE_LIMIT = 512;
a3e4271999-05-11Henrik Grubbström (Grubba)  string base;
ebc9881999-05-06Henrik Grubbström (Grubba)  object catalog_file; object data_file; mapping(string:int) new_entries_cache = ([]); mapping(string:object) active_objects = ([]); array(int) index;
e9857a1999-05-08Henrik Grubbström (Grubba)  array(string) index_acc; int acc_scale;
ebc9881999-05-06Henrik Grubbström (Grubba)  int next_offset; static class QuotaEntry { string name; int data_offset;
eed7141999-05-12Henrik Grubbström (Grubba)  static int usage;
ebc9881999-05-06Henrik Grubbström (Grubba)  static int quota; static void store() { LOCK();
eed7141999-05-12Henrik Grubbström (Grubba)  QD_WRITE(sprintf("QuotaEntry::store(): Usage for %O is now %O(%O)\n", name, usage, quota));
ebc9881999-05-06Henrik Grubbström (Grubba)  data_file->seek(data_offset);
eed7141999-05-12Henrik Grubbström (Grubba)  data_file->write(sprintf("%4c", usage));
ebc9881999-05-06Henrik Grubbström (Grubba)  UNLOCK(); } static void read() { LOCK(); data_file->seek(data_offset); string s = data_file->read(4);
eed7141999-05-12Henrik Grubbström (Grubba)  usage = 0; sscanf(s, "%4c", usage);
ebc9881999-05-06Henrik Grubbström (Grubba) 
01f6801999-06-20Henrik Grubbström (Grubba)  if (usage < 0) { // No negative usage. usage = 0; }
eed7141999-05-12Henrik Grubbström (Grubba)  QD_WRITE(sprintf("QuotaEntry::read(): Usage for %O is %O(%O)\n", name, usage, quota));
ebc9881999-05-06Henrik Grubbström (Grubba)  UNLOCK(); }
eed7141999-05-12Henrik Grubbström (Grubba)  void create(string n, int d_o, int q)
ebc9881999-05-06Henrik Grubbström (Grubba)  {
eed7141999-05-12Henrik Grubbström (Grubba)  QD_WRITE(sprintf("QuotaEntry(%O, %O, %O)\n", n, d_o, q));
ebc9881999-05-06Henrik Grubbström (Grubba)  name = n; data_offset = d_o;
eed7141999-05-12Henrik Grubbström (Grubba)  quota = q;
ebc9881999-05-06Henrik Grubbström (Grubba)  read(); } int check_quota(string uri, int amount) {
eed7141999-05-12Henrik Grubbström (Grubba)  QD_WRITE(sprintf("QuotaEntry::check_quota(%O, %O): usage:%d(%d)\n", uri, amount, usage, quota)); if (!quota) { // No quota at all. return 0; }
ebc9881999-05-06Henrik Grubbström (Grubba)  if (amount == 0x7fffffff) { // Workaround for FTP. return 1; }
eed7141999-05-12Henrik Grubbström (Grubba)  return(usage + amount <= quota);
ebc9881999-05-06Henrik Grubbström (Grubba)  } int allocate(string uri, int amount) {
eed7141999-05-12Henrik Grubbström (Grubba)  QD_WRITE(sprintf("QuotaEntry::allocate(%O, %O): usage:%d => %d(%d)\n", uri, amount, usage, usage + amount, quota));
ebc9881999-05-06Henrik Grubbström (Grubba) 
eed7141999-05-12Henrik Grubbström (Grubba)  usage += amount;
ebc9881999-05-06Henrik Grubbström (Grubba) 
01f6801999-06-20Henrik Grubbström (Grubba)  if (usage < 0) { // No negative usage... usage = 0; }
ebc9881999-05-06Henrik Grubbström (Grubba)  store();
eed7141999-05-12Henrik Grubbström (Grubba)  return(usage <= quota);
ebc9881999-05-06Henrik Grubbström (Grubba)  } int deallocate(string uri, int amount) { return(allocate(uri, -amount)); }
eed7141999-05-12Henrik Grubbström (Grubba)  int get_usage(string uri)
ebc9881999-05-06Henrik Grubbström (Grubba)  {
eed7141999-05-12Henrik Grubbström (Grubba)  return usage;
ebc9881999-05-06Henrik Grubbström (Grubba)  }
eed7141999-05-12Henrik Grubbström (Grubba)  void set_usage(string uri, int amount)
ebc9881999-05-06Henrik Grubbström (Grubba)  {
eed7141999-05-12Henrik Grubbström (Grubba)  usage = amount;
ebc9881999-05-06Henrik Grubbström (Grubba)  store(); } #if !constant(set_weak_flag) static int refs; void add_ref() { refs++; } void free_ref() { if (!(--refs)) { destruct(); } } } static class QuotaProxy { static object(QuotaEntry) master; function(string, int:int) check_quota; function(string, int:int) allocate; function(string, int:int) deallocate;
eed7141999-05-12Henrik Grubbström (Grubba)  function(string, int:void) set_usage; function(string:int) get_usage;
ebc9881999-05-06Henrik Grubbström (Grubba)  void create(object(QuotaEntry) m) { master = m; master->add_ref(); check_quota = master->check_quota; allocate = master->allocate; deallocate = master->deallocate;
eed7141999-05-12Henrik Grubbström (Grubba)  set_usage = master->set_usage; get_usage = master->get_usage;
ebc9881999-05-06Henrik Grubbström (Grubba)  } void destroy() { master->free_ref(); } #endif /* !constant(set_weak_flag) */ }
eed7141999-05-12Henrik Grubbström (Grubba)  static object read_entry(int offset, int|void quota)
ebc9881999-05-06Henrik Grubbström (Grubba)  {
eed7141999-05-12Henrik Grubbström (Grubba)  QD_WRITE(sprintf("QuotaDB::read_entry(%O, %O)\n", offset, quota));
ebc9881999-05-06Henrik Grubbström (Grubba)  catalog_file->seek(offset); string data = catalog_file->read(READ_BUF_SIZE); if (data == "") {
eed7141999-05-12Henrik Grubbström (Grubba)  QD_WRITE(sprintf("QuotaDB::read_entry(%O, %O): At EOF\n", offset, quota));
ebc9881999-05-06Henrik Grubbström (Grubba)  return 0; } int len; int data_offset; string key; sscanf(data[..7], "%4c%4c", len, data_offset); if (len > sizeof(data)) { key = data[8..] + catalog_file->read(len - sizeof(data)); len -= 8; if (sizeof(key) != len) { error(sprintf("Failed to read catalog entry at offset %d.\n" "len: %d, sizeof(key):%d\n", offset, len, sizeof(key))); } } else { key = data[8..len-1];
6fa7e81999-05-14Henrik Grubbström (Grubba)  catalog_file->seek(offset + 8 + sizeof(key));
ebc9881999-05-06Henrik Grubbström (Grubba)  }
eed7141999-05-12Henrik Grubbström (Grubba)  return QuotaEntry(key, data_offset, quota);
ebc9881999-05-06Henrik Grubbström (Grubba)  } static object open(string fname, int|void create_new) { object f = Stdio.File(); string mode = create_new?"rwc":"rw"; if (!f->open(fname, mode)) { error(sprintf("Failed to open quota file %O.\n", fname)); } if (f->try_lock && !f->try_lock()) { error(sprintf("Failed to lock quota file %O.\n", fname)); } return(f); }
e9857a1999-05-08Henrik Grubbström (Grubba)  static void init_index_acc() { /* Set up the index accellerator. * sizeof(index_acc) ~ sqrt(sizeof(index)) */ acc_scale = 1; if (sizeof(index)) { int i = sizeof(index)/2; while (i) { i /= 4;
8b5f0c1999-05-16Henrik Grubbström (Grubba)  acc_scale *= 2;
e9857a1999-05-08Henrik Grubbström (Grubba)  } }
8b5f0c1999-05-16Henrik Grubbström (Grubba)  index_acc = allocate((sizeof(index) + acc_scale -1)/acc_scale);
e9857a1999-05-08Henrik Grubbström (Grubba)  QD_WRITE(sprintf("QuotaDB()::init_index_acc(): " "sizeof(index):%d, sizeof(index_acc):%d acc_scale:%d\n", sizeof(index), sizeof(index_acc), acc_scale)); }
1a7b001999-05-14Henrik Grubbström (Grubba)  void rebuild_index()
ebc9881999-05-06Henrik Grubbström (Grubba)  {
a3e4271999-05-11Henrik Grubbström (Grubba)  array(string) new_keys = sort(indices(new_entries_cache)); int prev; array(int) new_index = ({}); foreach(new_keys, string key) {
8b5f0c1999-05-16Henrik Grubbström (Grubba)  QD_WRITE(sprintf("QuotaDB::rebuild_index(): key:%O lo:0 hi:%d\n", key, sizeof(index_acc)));
a3e4271999-05-11Henrik Grubbström (Grubba)  int lo; int hi = sizeof(index_acc);
eed7141999-05-12Henrik Grubbström (Grubba)  if (hi) { do {
366b791999-05-16Henrik Grubbström (Grubba)  // Loop invariants: // hi is an element > key. // lo-1 is an element < key.
eed7141999-05-12Henrik Grubbström (Grubba)  int probe = (lo + hi)/2;
8b5f0c1999-05-16Henrik Grubbström (Grubba)  QD_WRITE(sprintf("QuotaDB::rebuild_index(): acc: " "key:%O lo:%d probe:%d hi:%d\n", key, lo, probe, hi));
eed7141999-05-12Henrik Grubbström (Grubba)  if (!index_acc[probe]) { object e = read_entry(index[probe * acc_scale]); index_acc[probe] = e->name; } if (index_acc[probe] < key) {
366b791999-05-16Henrik Grubbström (Grubba)  lo = probe + 1;
eed7141999-05-12Henrik Grubbström (Grubba)  } else if (index_acc[probe] > key) { hi = probe; } else { /* Found */ // Shouldn't happen... break; }
366b791999-05-16Henrik Grubbström (Grubba)  } while(lo < hi);
eed7141999-05-12Henrik Grubbström (Grubba) 
366b791999-05-16Henrik Grubbström (Grubba)  if (lo < hi) {
eed7141999-05-12Henrik Grubbström (Grubba)  // Found... // Shouldn't happen, but... // Skip to the next key... continue;
a3e4271999-05-11Henrik Grubbström (Grubba)  }
8b5f0c1999-05-16Henrik Grubbström (Grubba)  if (hi) { hi *= acc_scale; lo = hi - acc_scale;
eed7141999-05-12Henrik Grubbström (Grubba) 
8b5f0c1999-05-16Henrik Grubbström (Grubba)  if (hi > sizeof(index)) { hi = sizeof(index); }
366b791999-05-16Henrik Grubbström (Grubba) 
8b5f0c1999-05-16Henrik Grubbström (Grubba)  do { // Same loop invariants as above. int probe = (lo + hi)/2; QD_WRITE(sprintf("QuotaDB::rebuild_index(): " "key:%O lo:%d probe:%d hi:%d\n", key, lo, probe, hi)); object e = read_entry(index[probe]); if (e->name < key) { lo = probe + 1; } else if (e->name > key) { hi = probe; } else { /* Found */ // Shouldn't happen... break; } } while (lo < hi); if (lo < hi) { // Found... // Shouldn't happen, but... // Skip to the next key... continue;
eed7141999-05-12Henrik Grubbström (Grubba)  }
a3e4271999-05-11Henrik Grubbström (Grubba)  }
366b791999-05-16Henrik Grubbström (Grubba)  new_index += index[prev..hi-1] + ({ new_entries_cache[key] });
eed7141999-05-12Henrik Grubbström (Grubba)  prev = hi; } else { new_index += ({ new_entries_cache[key] });
a3e4271999-05-11Henrik Grubbström (Grubba)  } }
8b5f0c1999-05-16Henrik Grubbström (Grubba)  // Add the trailing elements... new_index += index[prev..]; QD_WRITE("Index rebuilt.\n");
a3e4271999-05-11Henrik Grubbström (Grubba)  LOCK(); object index_file = open(base + ".index.new", 1); string to_write = sprintf("%@4c", new_index); if (index_file->write(to_write) != sizeof(to_write)) { index_file->close(); rm(base + ".index.new"); } else { mv(base + ".index.new", base + ".index"); } index = new_index; init_index_acc(); UNLOCK(); foreach(new_keys, string key) { m_delete(new_entries_cache, key); }
ebc9881999-05-06Henrik Grubbström (Grubba)  }
eed7141999-05-12Henrik Grubbström (Grubba)  static object low_lookup(string key, int quota)
ebc9881999-05-06Henrik Grubbström (Grubba)  {
eed7141999-05-12Henrik Grubbström (Grubba)  QD_WRITE(sprintf("QuotaDB::low_lookup(%O, %O)\n", key, quota));
ebc9881999-05-06Henrik Grubbström (Grubba) 
a3e4271999-05-11Henrik Grubbström (Grubba)  int cat_offset;
ebc9881999-05-06Henrik Grubbström (Grubba) 
a3e4271999-05-11Henrik Grubbström (Grubba)  if (!zero_type(cat_offset = new_entries_cache[key])) {
eed7141999-05-12Henrik Grubbström (Grubba)  QD_WRITE(sprintf("QuotaDB::low_lookup(%O, %O): " "Found in new entries cache.\n", key, quota)); return read_entry(cat_offset, quota);
e9857a1999-05-08Henrik Grubbström (Grubba)  } /* Try the index file. */
ebc9881999-05-06Henrik Grubbström (Grubba) 
e9857a1999-05-08Henrik Grubbström (Grubba)  /* First use the accellerated index. */ int lo; int hi = sizeof(index_acc);
eed7141999-05-12Henrik Grubbström (Grubba)  if (hi) { do {
366b791999-05-16Henrik Grubbström (Grubba)  // Loop invariants: // hi is an element that is > key. // lo-1 is an element that is < key.
eed7141999-05-12Henrik Grubbström (Grubba)  int probe = (lo + hi)/2;
ebc9881999-05-06Henrik Grubbström (Grubba) 
366b791999-05-16Henrik Grubbström (Grubba)  QD_WRITE(sprintf("QuotaDB:low_lookup(%O): " "In acc: lo:%d, probe:%d, hi:%d\n", key, lo, probe, hi));
eed7141999-05-12Henrik Grubbström (Grubba)  if (!index_acc[probe]) { object e = read_entry(index[probe * acc_scale], quota);
e9857a1999-05-08Henrik Grubbström (Grubba) 
eed7141999-05-12Henrik Grubbström (Grubba)  index_acc[probe] = e->name;
e9857a1999-05-08Henrik Grubbström (Grubba) 
eed7141999-05-12Henrik Grubbström (Grubba)  if (key == e->name) { /* Found in e */ QD_WRITE(sprintf("QuotaDB:low_lookup(%O): In acc: Found at %d\n", key, probe * acc_scale)); return e; } } if (index_acc[probe] < key) {
366b791999-05-16Henrik Grubbström (Grubba)  lo = probe + 1;
eed7141999-05-12Henrik Grubbström (Grubba)  } else if (index_acc[probe] > key) { hi = probe; } else { /* Found */
e9857a1999-05-08Henrik Grubbström (Grubba)  QD_WRITE(sprintf("QuotaDB:low_lookup(%O): In acc: Found at %d\n", key, probe * acc_scale));
eed7141999-05-12Henrik Grubbström (Grubba)  return read_entry(index[probe * acc_scale], quota);
e9857a1999-05-08Henrik Grubbström (Grubba)  }
366b791999-05-16Henrik Grubbström (Grubba)  } while(lo < hi); // At this point hi is the first element that is > key. // Not in the accellerated index.
ebc9881999-05-06Henrik Grubbström (Grubba) 
366b791999-05-16Henrik Grubbström (Grubba)  if (hi) { // Go to disk hi *= acc_scale; lo = hi - acc_scale;
8b5f0c1999-05-16Henrik Grubbström (Grubba)  if (hi > sizeof(index)) { hi = sizeof(index); }
366b791999-05-16Henrik Grubbström (Grubba)  do { // Same loop invariant as above. int probe = (lo + hi)/2; QD_WRITE(sprintf("QuotaDB:low_lookup(%O): lo:%d, probe:%d, hi:%d\n", key, lo, probe, hi)); object e = read_entry(index[probe], quota);
eed7141999-05-12Henrik Grubbström (Grubba) 
366b791999-05-16Henrik Grubbström (Grubba)  if (e->name < key) { lo = probe + 1; } else if (e->name > key) { hi = probe; } else { /* Found */ QD_WRITE(sprintf("QuotaDB:low_lookup(%O): Found at %d\n", key, probe)); return e; } } while (lo < hi); }
e9857a1999-05-08Henrik Grubbström (Grubba)  } QD_WRITE(sprintf("QuotaDB::low_lookup(%O): Not found\n", key)); return 0;
ebc9881999-05-06Henrik Grubbström (Grubba)  } object lookup(string key, int quota) { QD_WRITE(sprintf("QuotaDB::lookup(%O, %O)\n", key, quota)); LOCK(); object res; if (res = active_objects[key]) { QD_WRITE(sprintf("QuotaDB::lookup(%O, %O): User in active objects.\n", key, quota)); #if constant(set_weak_flag) return res; #else /* !constant(set_weak_flag) */ return QuotaProxy(res); #endif /* constant(set_weak_flag) */ }
eed7141999-05-12Henrik Grubbström (Grubba)  if (res = low_lookup(key, quota)) {
e9857a1999-05-08Henrik Grubbström (Grubba)  active_objects[key] = res; #if constant(set_weak_flag)
ebc9881999-05-06Henrik Grubbström (Grubba)  return res;
e9857a1999-05-08Henrik Grubbström (Grubba) #else /* !constant(set_weak_flag) */ return QuotaProxy(res); #endif /* constant(set_weak_flag) */
ebc9881999-05-06Henrik Grubbström (Grubba)  } QD_WRITE(sprintf("QuotaDB::lookup(%O, %O): New user.\n", key, quota)); // Search to EOF. data_file->seek(-1); data_file->read(1); catalog_file->seek(next_offset); // We should now be at EOF. int data_offset = data_file->tell(); // Initialize.
eed7141999-05-12Henrik Grubbström (Grubba)  if (data_file->write(sprintf("%4c", 0)) != 4) {
ebc9881999-05-06Henrik Grubbström (Grubba)  error(sprintf("write() failed for quota data file!\n")); } string entry = sprintf("%4c%4c%s", sizeof(key)+8, data_offset, key); if (catalog_file->write(entry) != sizeof(entry)) { error(sprintf("write() failed for quota catalog file!\n")); } new_entries_cache[key] = next_offset; next_offset = catalog_file->tell(); if (sizeof(new_entries_cache) > CACHE_SIZE_LIMIT) { rebuild_index(); } // low_lookup will always succeed at this point.
eed7141999-05-12Henrik Grubbström (Grubba)  return low_lookup(key, quota);
ebc9881999-05-06Henrik Grubbström (Grubba)  } void create(string base_name, int|void create_new) {
a3e4271999-05-11Henrik Grubbström (Grubba)  base = base_name;
ebc9881999-05-06Henrik Grubbström (Grubba)  catalog_file = open(base_name + ".cat", create_new); data_file = open(base_name + ".data", create_new);
a3e4271999-05-11Henrik Grubbström (Grubba)  object index_file = open(base_name + ".index", 1);
ebc9881999-05-06Henrik Grubbström (Grubba)  #if constant(set_weak_flag) set_weak_flag(active_objects, 1); #endif /* constant(set_weak_flag) */ /* Initialize the new_entries table. */ array index_st = index_file->stat(); if (!index_st || !sizeof(index_st)) { error(sprintf("stat() failed for quota index file!\n")); } array data_st = data_file->stat(); if (!data_st || !sizeof(data_st)) { error(sprintf("stat() failed for quota data file!\n")); } if (index_st[1] < 0) { error("quota index file isn't a regular file!\n"); } if (data_st[1] < 0) { error("quota data file isn't a regular file!\n"); } if (data_st[1] < index_st[1]) { error("quota data file is shorter than the index file!\n"); } if (index_st[1] & 3) { error("quota index file has odd length!\n"); } if (data_st[1] & 3) { error("quota data file has odd length!\n"); } /* Read the index, and find the last entry in the catalog file. */ int i; array(string) index_str = index_file->read()/4; index = allocate(sizeof(index_str));
a3e4271999-05-11Henrik Grubbström (Grubba)  if (sizeof(index_str) && (sizeof(index_str[-1]) != 4)) {
ebc9881999-05-06Henrik Grubbström (Grubba)  error("Truncated read of the index file!\n"); } foreach(index_str, string offset_str) { int offset; sscanf(offset_str, "%4c", offset); index[i++] = offset; if (offset > next_offset) { next_offset = offset; } }
e9857a1999-05-08Henrik Grubbström (Grubba)  init_index_acc();
ebc9881999-05-06Henrik Grubbström (Grubba)  if (sizeof(index)) { /* Skip past the last entry in the catalog file */ mixed entry = read_entry(next_offset); next_offset = catalog_file->tell(); } if (index_st[1] < data_st[1]) { /* Put everything else in the new_entries_cache */ while (mixed entry = read_entry(next_offset)) { new_entries_cache[entry->name] = next_offset; next_offset = catalog_file->tell(); } /* Clean up the index. */ rebuild_index(); } } }
69e4cd2000-03-09Martin Stjernholm 
df6c032000-08-09Per Hedbor #define CTX()
f352562000-09-24Henrik Grubbström (Grubba) class EScope(string scope)
df6c032000-08-09Per Hedbor { void delete( string var ) { RXML.Context ctx = RXML.get_context( ); ctx->delete_var( var, scope ); } string name() { RXML.Context ctx = RXML.get_context( ); return scope == "_" ? ctx->current_scope() : scope; }
f352562000-09-24Henrik Grubbström (Grubba)  static mixed `[]( string what )
df6c032000-08-09Per Hedbor  { RXML.Context ctx = RXML.get_context( ); return ctx->get_var( what, scope ); }
f352562000-09-24Henrik Grubbström (Grubba)  static mixed `->( string what )
df6c032000-08-09Per Hedbor  { return `[]( what ); }
f352562000-09-24Henrik Grubbström (Grubba)  static mixed `[]=( string what, mixed nval )
df6c032000-08-09Per Hedbor  { RXML.Context ctx = RXML.get_context( ); ctx->set_var( what, nval, scope ); return nval; }
f352562000-09-24Henrik Grubbström (Grubba)  static mixed `->=( string what, mixed nval )
df6c032000-08-09Per Hedbor  { return `[]=( what, nval ); }
f352562000-09-24Henrik Grubbström (Grubba)  static array(string) _indices( )
df6c032000-08-09Per Hedbor  { RXML.Context ctx = RXML.get_context( ); return ctx->list_var( scope ); }
f352562000-09-24Henrik Grubbström (Grubba)  static array(string) _values( )
df6c032000-08-09Per Hedbor  { RXML.Context ctx = RXML.get_context( ); return map( ctx->list_var( scope ), `[] ); } } class SRestore { mapping osc = ([]); void destroy() { foreach( indices( osc ), string o ) add_constant( o, osc[o] ); add_constant( "roxen", roxenp() ); } } SRestore add_scope_constants( string|void name ) { SRestore res = SRestore(); mapping ac = all_constants(); if(!name) name = "";
85a1bb2000-08-10Per Hedbor  if( RXML.get_context() )
df6c032000-08-09Per Hedbor  {
85a1bb2000-08-10Per Hedbor  foreach( RXML.get_context()->list_scopes()|({"_"}), string scope ) { res->osc[ name+scope ] = ac[ name+scope ]; add_constant( name+scope, EScope( scope ) ); }
df6c032000-08-09Per Hedbor  } return res; }
7035032000-08-23Martin Nilsson //! A mapping suitable for Parser.HTML.add_entities to initialize it //! to transform the standard character reference entities. mapping(string:string) parser_charref_table = lambda () { mapping(string:string) table = ([]); for (int i = 0; i < sizeof (replace_entities); i++) { string chref = replace_entities[i]; table[chref[1..sizeof (chref) - 2]] = replace_values[i]; } return table; }();
f4c4d52000-08-27Martin Stjernholm //! The inverse mapping to parser_charref_table. mapping(string:string) inverse_charref_table = lambda () { mapping(string:string) table = ([]); for (int i = 0; i < sizeof (replace_entities); i++) { string chref = replace_entities[i]; table[replace_values[i]] = chref[1..sizeof (chref) - 2]; } return table; }(); string decode_charref (string chref) //! Decodes a character reference entity either on symbolic or numeric //! form. Returns zero if the reference isn't recognized. { if (sizeof (chref) <= 2 || chref[0] != '&' || chref[-1] != ';') return 0; if (chref[1] != '#') return parser_charref_table[chref[1..sizeof (chref) - 2]]; if ((<'x', 'X'>)[chref[2]]) { if (sscanf (chref, "&%*2s%x;%*c", int c) == 2) return sprintf ("%c", c); } else if (sscanf (chref, "&%*c%d;%*c", int c) == 2) return sprintf ("%c", c); return 0; }
425fc62000-09-21Per Hedbor string|program safe_compile( string code ) { program ret;
6465b92000-09-27Per Hedbor  roxenloader.LowErrorContainer ec = roxenloader.LowErrorContainer();
425fc62000-09-21Per Hedbor  roxenloader.push_compile_error_handler( ec ); catch(ret = compile_string( code ));
6465b92000-09-27Per Hedbor  roxenloader.pop_compile_error_handler( );
425fc62000-09-21Per Hedbor  if( !ret ) return ec->get(); return ret; }
f4c4d52000-08-27Martin Stjernholm string encode_charref (string char) //! Encodes a character to a character reference entity. The symbolic
d3beb02000-08-27Martin Stjernholm //! form is preferred over the numeric. The decimal variety of the //! numeric form is used (since it's understood better than the //! hexadecimal form by at least Netscape 4).
f4c4d52000-08-27Martin Stjernholm { if (string chref = inverse_charref_table[char]) return "&" + chref + ";";
d3beb02000-08-27Martin Stjernholm  return sprintf ("&#%d;", char[0]);
f4c4d52000-08-27Martin Stjernholm }
7035032000-08-23Martin Nilsson 
df6c032000-08-09Per Hedbor 
69e4cd2000-03-09Martin Stjernholm // RXML complementary stuff shared between configurations. class ScopeRoxen { inherit RXML.Scope; string pike_version=predef::version(); int ssl_strength=0; #if constant(SSL) void create() { ssl_strength=40;
c4ee172000-04-06Henrik Grubbström (Grubba) #if constant(SSL.constants.CIPHER_des)
69e4cd2000-03-09Martin Stjernholm  if(SSL.constants.CIPHER_algorithms[SSL.constants.CIPHER_des]) ssl_strength=128; if(SSL.constants.CIPHER_algorithms[SSL.constants.CIPHER_3des]) ssl_strength=168;
c4ee172000-04-06Henrik Grubbström (Grubba) #endif /* !constant(SSL.constants.CIPHER_des) */
69e4cd2000-03-09Martin Stjernholm  } #endif
7035032000-08-23Martin Nilsson  mixed `[] (string var, void|RXML.Context c, void|string scope) {
69e4cd2000-03-09Martin Stjernholm  switch(var) { case "uptime":
7e9a0b2000-09-16Per Hedbor  CACHE(c->id,1);
dbf9912000-03-19Martin Nilsson  return (time(1)-roxenp()->start_time);
69e4cd2000-03-09Martin Stjernholm  case "uptime-days":
7e9a0b2000-09-16Per Hedbor  CACHE(c->id,3600*2);
dbf9912000-03-19Martin Nilsson  return (time(1)-roxenp()->start_time)/3600/24;
69e4cd2000-03-09Martin Stjernholm  case "uptime-hours":
7e9a0b2000-09-16Per Hedbor  CACHE(c->id,1800);
dbf9912000-03-19Martin Nilsson  return (time(1)-roxenp()->start_time)/3600;
69e4cd2000-03-09Martin Stjernholm  case "uptime-minutes":
7e9a0b2000-09-16Per Hedbor  CACHE(c->id,60);
dbf9912000-03-19Martin Nilsson  return (time(1)-roxenp()->start_time)/60;
69e4cd2000-03-09Martin Stjernholm  case "hits-per-minute":
7e9a0b2000-09-16Per Hedbor  CACHE(c->id,2);
dbf9912000-03-19Martin Nilsson  return c->id->conf->requests / ((time(1)-roxenp()->start_time)/60 + 1);
69e4cd2000-03-09Martin Stjernholm  case "hits":
7e9a0b2000-09-16Per Hedbor  NOCACHE(c->id);
69e4cd2000-03-09Martin Stjernholm  return c->id->conf->requests; case "sent-mb":
7e9a0b2000-09-16Per Hedbor  CACHE(c->id,10);
69e4cd2000-03-09Martin Stjernholm  return sprintf("%1.2f",c->id->conf->sent / (1024.0*1024.0)); case "sent":
7e9a0b2000-09-16Per Hedbor  NOCACHE(c->id);
69e4cd2000-03-09Martin Stjernholm  return c->id->conf->sent; case "sent-per-minute":
7e9a0b2000-09-16Per Hedbor  CACHE(c->id,2);
dbf9912000-03-19Martin Nilsson  return c->id->conf->sent / ((time(1)-roxenp()->start_time)/60 || 1);
69e4cd2000-03-09Martin Stjernholm  case "sent-kbit-per-second":
7e9a0b2000-09-16Per Hedbor  CACHE(c->id,2);
69e4cd2000-03-09Martin Stjernholm  return sprintf("%1.2f",((c->id->conf->sent*8)/1024.0/
dbf9912000-03-19Martin Nilsson  (time(1)-roxenp()->start_time || 1)));
69e4cd2000-03-09Martin Stjernholm  case "ssl-strength": return ssl_strength; case "pike-version": return pike_version; case "version":
dbf9912000-03-19Martin Nilsson  return roxenp()->version();
88bff12000-09-12Per Hedbor  case "base-version": return __roxen_version__; case "build": return __roxen_build__;
69e4cd2000-03-09Martin Stjernholm  case "time":
7e9a0b2000-09-16Per Hedbor  CACHE(c->id,1);
69e4cd2000-03-09Martin Stjernholm  return time(1); case "server": return c->id->conf->query("MyWorldLocation");
9705b92000-07-02Martin Nilsson  case "domain": string tmp=c->id->conf->query("MyWorldLocation"); sscanf(tmp, "%*s//%s", tmp); sscanf(tmp, "%s:", tmp); sscanf(tmp, "%s/", tmp); return tmp;
7035032000-08-23Martin Nilsson  case "locale":
7e9a0b2000-09-16Per Hedbor  NOCACHE(c->id);
7035032000-08-23Martin Nilsson  return roxenp()->locale->get(); default: return RXML.nil;
69e4cd2000-03-09Martin Stjernholm  } :: `[] (var, c, scope); } array(string) _indices() { return ({"uptime", "uptime-days", "uptime-hours", "uptime-minutes", "hits-per-minute", "hits", "sent-mb", "sent", "sent-per-minute", "sent-kbit-per-second", "ssl-strength",
7035032000-08-23Martin Nilsson  "pike-version", "version", "time", "server", "domain", "locale"});
69e4cd2000-03-09Martin Stjernholm  } string _sprintf() { return "RXML.Scope(roxen)"; } } class ScopePage { inherit RXML.Scope; constant converter=(["fgcolor":"fgcolor", "bgcolor":"bgcolor", "theme-bgcolor":"theme_bgcolor", "theme-fgcolor":"theme_fgcolor", "theme-language":"theme_language"]); constant in_defines=aggregate_multiset(@indices(converter)); mixed `[] (string var, void|RXML.Context c, void|string scope) {
7e9a0b2000-09-16Per Hedbor  NOCACHE(c->id);
971ed32000-03-20Martin Stjernholm  switch (var) { case "pathinfo": return c->id->misc->path_info; }
69e4cd2000-03-09Martin Stjernholm  if(in_defines[var]) return c->id->misc->defines[converter[var]]; if(objectp(c->id->misc->scope_page[var])) return c->id->misc->scope_page[var]->rxml_var_eval(c, var, "page"); return c->id->misc->scope_page[var]; } mixed `[]= (string var, mixed val, void|RXML.Context c, void|string scope_name) {
971ed32000-03-20Martin Stjernholm  switch (var) { case "pathinfo": return c->id->misc->path_info = val; }
69e4cd2000-03-09Martin Stjernholm  if(in_defines[var]) return c->id->misc->defines[converter[var]]=val; return c->id->misc->scope_page[var]=val; } array(string) _indices(void|RXML.Context c) { if(!c) return ({});
7e9a0b2000-09-16Per Hedbor  NOCACHE(c->id);
69e4cd2000-03-09Martin Stjernholm  array ind=indices(c->id->misc->scope_page); foreach(indices(in_defines), string def) if(c->id->misc->defines[converter[def]]) ind+=({def});
a458af2000-03-20Martin Stjernholm  return ind + ({"pathinfo"});
69e4cd2000-03-09Martin Stjernholm  } void m_delete (string var, void|RXML.Context c, void|string scope_name) { if(!c) return;
971ed32000-03-20Martin Stjernholm  switch (var) { case "pathinfo": predef::m_delete (c->id->misc, "pathinfo"); return; }
69e4cd2000-03-09Martin Stjernholm  if(in_defines[var]) { if(var[0..4]=="theme") predef::m_delete(c->id->misc->defines, converter[var]); else ::m_delete(var, c, scope_name);
971ed32000-03-20Martin Stjernholm  return;
69e4cd2000-03-09Martin Stjernholm  } predef::m_delete(c->id->misc->scope_page, var); } string _sprintf() { return "RXML.Scope(page)"; } }
7035032000-08-23Martin Nilsson class ScopeCookie { inherit RXML.Scope;
69e4cd2000-03-09Martin Stjernholm 
7035032000-08-23Martin Nilsson  mixed `[] (string var, void|RXML.Context c, void|string scope) { if(!c) return RXML.nil;
7e9a0b2000-09-16Per Hedbor  NOCACHE(c->id);
7035032000-08-23Martin Nilsson  return c->id->cookies[var]; } mixed `[]= (string var, mixed val, void|RXML.Context c, void|string scope_name) { if(c && c->id->cookies[var]!=val) { c->id->cookies[var]=val; add_http_header(c->id->misc->defines[" _extra_heads"], "Set-Cookie", http_encode_cookie(var)+ "="+http_encode_cookie( (string)(val||"") )+ "; expires="+http_date(time(1)+(3600*24*365*2))+"; path=/");
9bf1182000-08-12Martin Stjernholm  }
7035032000-08-23Martin Nilsson  return RXML.nil; } array(string) _indices(void|RXML.Context c) { if(!c) return ({});
7e9a0b2000-09-16Per Hedbor  NOCACHE(c->id);
7035032000-08-23Martin Nilsson  return indices(c->id->cookies); } void m_delete (string var, void|RXML.Context c, void|string scope_name) { if(!c || !c->id->cookies[var]) return; predef::m_delete(c->id->cookies, var); add_http_header(c->id->misc->defines[" _extra_heads"], "Set-Cookie", http_encode_cookie(var)+"=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/"); } string _sprintf() { return "RXML.Scope(Cookie)"; } } RXML.Scope scope_roxen=ScopeRoxen(); RXML.Scope scope_page=ScopePage(); RXML.Scope scope_cookie=ScopeCookie();
9bf1182000-08-12Martin Stjernholm 
3c4c6e2000-11-02Per Hedbor class ScopeModVar { class Modules( mapping module, string sname ) { class ModVars( RoxenModule mod ) { class Var(object var ) { inherit RXML.Value; mixed cast( string type ) { switch( type ) { case "string": return (string)var->query(); case "int": return (int)var->query(); case "float": return (float)var->query(); case "array": return (array)var->query(); } } mixed rxml_var_eval( RXML.Context ctx, string vn, string scp, void|RXML.Type type ) { mixed res = var->query(); if( type ) res = type->encode( res ); return res; } } mixed cast( string type ) { switch( type ) { case "string": return roxenp()->find_module( sname ) ? roxenp()->find_module( sname )->get_name() : sname; } } array _values() { return map( _indices(), `[] ); } array _indices() { mapping m = mod->getvars(); return sort( filter( indices(m), lambda(string n) { return m[n]->get_flags()&VAR_PUBLIC; } ) ); } mixed `[]( string what ) { object var; if( (var = mod->getvar( what )) ) { if( (var->get_flags() & VAR_PUBLIC) ) return Var( var ); else RXML.parse_error("The variable "+what+" is not public\n"); } else RXML.parse_error("The variable "+what+" does not exist\n"); } } mixed cast( string type ) { switch( type ) { case "string": return roxenp()->find_module( sname ) ? roxenp()->find_module( sname )->get_name() : sname; } } array _values() { return map( _indices(), `[] ); } array _indices() { return sort(indices( module )); } mixed `[]( string what ) { mixed mod; if( (mod = (int)what) ) if( (mod = module[ mod-1 ]) ) return ModVars( module[mod-1] );
343ee62000-11-06Per Hedbor // else // RXML.parse_error("The module copy #"+mod+ // " does not exist for this module\n");
3c4c6e2000-11-02Per Hedbor  return ModVars( values( module )[0] )[ what ]; } } mixed `[]( string what ) { if( what == "site" ) return Modules( ([ 0:RXML.get_context()->id->conf ]), "site" ); if( what == "global" ) return Modules( ([ 0:roxenp() ]), "roxen" ); if( !RXML.get_context()->id->conf->modules[ what ] ) RXML.parse_error("The module "+what+" does not exist\n"); return Modules( RXML.get_context()->id->conf->modules[ what ], what ); } array _values( ) { return map( _indices(), `[] ); } array _indices() { return ({ "site" }) + sort(indices(RXML.get_context()->id->conf->modules)); } } class FormScope( mapping variables ) { inherit RXML.Scope; class AVal( array var, string name ) { mixed cast( string type ) { switch( type ) { case "string": return var*"\0"; } } array _indices() { return indices( variables ); } array _values() { return map( _indices(), `[] ); } mixed `[]=( string index, mixed newval ) { mixed res; if( int ind = (int)index ) if( (ind > sizeof( var )) || ((ind < 0) && (-ind > sizeof( var ) )) ) RXML.parse_error( "Array not big enough for index %d.\n", ind ); else if( ind < 0 )
02919a2000-11-03Leif Stensson  var[ind] = newval;
3c4c6e2000-11-02Per Hedbor  else
02919a2000-11-03Leif Stensson  var[ind-1] = newval;
3c4c6e2000-11-02Per Hedbor  else RXML.parse_error( "Cannot index array with %O\n", ind ); RXML.get_context()->id->variables[name] = ((array(string))var)*"\0";
02919a2000-11-03Leif Stensson  return newval;
3c4c6e2000-11-02Per Hedbor  } mixed `[]( string index ) { if( int ind = (int)index ) if( (ind > sizeof( var )) || ((ind < 0) && (-ind > sizeof( var ) )) ) RXML.parse_error( "Array not big enough for index %d.\n", ind ); else if( ind < 0 ) return var[ind]; else return var[ind-1]; else RXML.parse_error( "Cannot index array with %O\n", ind ); } }
8c6fbe2000-11-02Per Hedbor  mixed `[]=( string index, mixed newval ) { variables[ index ] = newval; }
3c4c6e2000-11-02Per Hedbor  mixed `[]( string what ) { mixed q = variables[ what ];
9a3dbd2000-11-16Per Hedbor  if( !stringp(q) ) return q;
3c4c6e2000-11-02Per Hedbor  q /= "\0"; if( sizeof( q ) == 1 ) return q[0]; return AVal( q, what ); } array _values( ) { return map( _indices(), `[] ); } array _indices() { return indices( variables ); } } ScopeModVar scope_modvar = ScopeModVar();
69e4cd2000-03-09Martin Stjernholm RXML.TagSet entities_tag_set = class // This tag set always has the lowest priority. { inherit RXML.TagSet; void prepare_context (RXML.Context c) { c->add_scope("roxen",scope_roxen); c->id->misc->scope_page=([]); c->add_scope("page",scope_page);
7035032000-08-23Martin Nilsson  c->add_scope("cookie", scope_cookie);
3c4c6e2000-11-02Per Hedbor  c->add_scope("modvar", scope_modvar); c->add_scope("form", FormScope( c->id->variables) );
7035032000-08-23Martin Nilsson  c->add_scope("client", c->id->client_var);
69e4cd2000-03-09Martin Stjernholm  c->add_scope("var", ([]) ); } void create (string name) { ::create (name);
7eeec72000-07-06Martin Stjernholm  // Note: No string entities are replaced when the result type for // the parser is t_xml or t_html.
9bf1182000-08-12Martin Stjernholm  add_string_entities (parser_charref_table);
69e4cd2000-03-09Martin Stjernholm  } } ("entities_tag_set");
dbf9912000-03-19Martin Nilsson 
b92a1c2000-08-14Martin Stjernholm 
dbf9912000-03-19Martin Nilsson constant monthnum=(["Jan":0, "Feb":1, "Mar":2, "Apr":3, "May":4, "Jun":5, "Jul":6, "Aug":7, "Sep":8, "Oct":9, "Nov":10, "Dec":11, "jan":0, "feb":1, "mar":2, "apr":3, "may":4, "jun":5, "jul":6, "aug":7, "sep":8, "oct":9, "nov":10, "dec":11,]); #define MAX_SINCE_CACHE 16384 static mapping(string:int) since_cache=([ ]); array(int) parse_since(string date) { if(!date || sizeof(date)<14) return({0,-1}); int t=0, length = -1; #if constant(mktime)
f6deda2000-07-11Martin Nilsson  string dat=lower_case(date); sscanf(dat+"; length=", "%*s, %s; length=%d", dat, length);
dbf9912000-03-19Martin Nilsson  if(!(t=since_cache[dat])) { int day, year = -1, month, hour, minute, second; string m; if(sscanf(dat, "%d-%s-%d %d:%d:%d", day, m, year, hour, minute, second)>2) { month=monthnum[m]; } else if(dat[2]==',') { // I bet a buck that this never happens sscanf(dat, "%*s, %d %s %d %d:%d:%d", day, m, year, hour, minute, second); month=monthnum[m]; } else if(!(int)dat) { sscanf(dat, "%*[^ ] %s %d %d:%d:%d %d", m, day, hour, minute, second, year); month=monthnum[m]; } else { sscanf(dat, "%d %s %d %d:%d:%d", day, m, year, hour, minute, second); month=monthnum[m]; } if(year >= 0) { // Fudge year to be localtime et al compatible. if (year < 60) { // Assume year 0 - 59 is really year 2000 - 2059. // Can't people stop using two digit years? year += 100; } else if (year >= 1900) { year -= 1900; } catch {
df6c032000-08-09Per Hedbor  t = mktime(second, minute, hour, day, month, year, 0, 0);
dbf9912000-03-19Martin Nilsson  }; } else { report_debug("Could not parse \""+date+"\" to a time int."); } if (sizeof(since_cache) > MAX_SINCE_CACHE) since_cache = ([]); since_cache[dat]=t; } #endif /* constant(mktime) */ return ({ t, length }); } // OBSOLETED by parse_since() int is_modified(string a, int t, void|int len) { array vals=parse_since(a); if(len && len!=vals[1]) return 0; if(vals[0]<t) return 0; return 1; } int httpdate_to_time(string date) { return parse_since(date)[0]||-1; }
31d1642000-03-26Martin Nilsson 
3580f52000-09-03Per Hedbor void set_cookie( RequestID id, string name, string value, int|void expire_time_delta, string|void domain, string|void path ) //! Set the cookie specified by 'name' to 'value'. //! Sends a Set-Cookie header. //! //! The expire_time_delta, domain and path arguments are optional. //! //! If the expire_time_delta variable is -1, the cookie is set to //! //! expire five years in the future. If it is 0 or ommited, no expire //! information is sent to the client. This usualy results in the cookie //! being kept until the browser is exited. { if( expire_time_delta = -1 ) expire_time_delta = (3600*(24*365*5)); string cookie = (http_encode_cookie( name )+"="+ http_encode_cookie( value )); if( expire_time_delta ) cookie += "; expires="+http_date( expire_time_delta+time(1) ); if( domain ) cookie += "; domain="+http_encode_cookie( domain ); if( path ) cookie += "; path="+http_encode_cookie( path ); if(!id->misc->moreheads) id->misc->moreheads = ([]); add_http_header( id->misc->moreheads, "Set-Cookie",cookie ); } void remove_cookie( RequestID id, string name, string value, string|void domain, string|void path ) //! Remove the cookie specified by 'name'. //! Sends a Set-Cookie header with an expire time of 00:00 1/1 1970. //! The domain and path arguments are optional. { set_cookie( id, name, value, -time(1), domain, path ); }
c9dd7f2000-11-21Per Hedbor void add_cache_stat_callback( RequestID id, string file, int mtime ) { while( id->misc->orig ) id = id->misc->orig; if( !id->misc->_cachecallbacks ) return; id->misc->_cachecallbacks += ({ lambda( RequestID id, object key ) { Stat st = file_stat( file ); if( !st || (st[ST_MTIME] != mtime) ) { destruct( key ); return 0; } return 1; } }); }
c3c6322000-09-20Per Hedbor void add_cache_callback( RequestID id,function(RequestID,object:int) callback )
a456472000-08-31Per Hedbor //! The request id object is not yet fully initialized in this callback. //! The only valid fields are raw_url and request_headers.
c3c6322000-09-20Per Hedbor //! The second argument is the cache key. Destroying it will enforce //! exiration of the entry from the data cache.
a456472000-08-31Per Hedbor { while( id->misc->orig ) id = id->misc->orig;
129ed72000-09-25Per Hedbor  if( !id->misc->_cachecallbacks ) return;
a456472000-08-31Per Hedbor  id->misc->_cachecallbacks |= ({ callback }); }
129ed72000-09-25Per Hedbor string get_server_url(Configuration c) {
31d1642000-03-26Martin Nilsson  string url=c->query("MyWorldLocation"); if(stringp(url) && sizeof(url)) return url; array(string) urls=c->query("URLs"); return get_world(urls); } string get_world(array(string) urls) { if(!sizeof(urls)) return 0; string url=urls[0]; foreach( ({"http:","fhttp:","https:","ftp:"}), string p) foreach(urls, string u) if(u[0..sizeof(p)-1]==p) { url=u; break; }
f70aa72000-03-28Martin Nilsson  string protocol, server, path="";
31d1642000-03-26Martin Nilsson  int port; if(sscanf(url, "%s://%s:%d/%s", protocol, server, port, path)!=4 &&
f70aa72000-03-28Martin Nilsson  sscanf(url, "%s://%s:%d", protocol, server, port)!=3 && sscanf(url, "%s://%s/%s", protocol, server, path)!=3 && sscanf(url, "%s://%s", protocol, server)!=2 )
31d1642000-03-26Martin Nilsson  return 0; if(protocol=="fhttp") protocol="http"; array hosts=({ gethostname() }), dns; catch(dns=Protocols.DNS.client()->gethostbyname(hosts[0])); if(dns && sizeof(dns)) hosts+=dns[2]+dns[1]; foreach(hosts, string host) if(glob(server, host)) { server=host; break; } if(port) return sprintf("%s://%s:%d/%s", protocol, server, port, path); return sprintf("%s://%s/%s", protocol, server, path); }
c166222000-08-09Per Hedbor 
b92a1c2000-08-14Martin Stjernholm RoxenModule get_owning_module (object|function thing) //! Tries to find out which module the thing belongs to, if any. The //! thing can be e.g. a module object, a Tag object or a simple_tag //! callback. {
566c072000-11-02Per Hedbor  if (functionp (thing)) thing = function_object (thing); if (objectp (thing)) { if (thing->is_module) return thing; object o = [object]thing; while (object parent = functionp (object_program (o)) && function_object (object_program (o))) {
b92a1c2000-08-14Martin Stjernholm  // FIXME: This way of finding the module for a tag is ugly.
566c072000-11-02Per Hedbor  if (parent->is_module) return parent; o = parent;
b92a1c2000-08-14Martin Stjernholm  }
566c072000-11-02Per Hedbor  // So. No such luck. Now we have a problem. This hack finds the // owning module of simple_tag and simple_pi_tag objects. if( thing->_do_return ) return get_owning_module( thing->_do_return );
b92a1c2000-08-14Martin Stjernholm  } return 0; } Configuration get_owning_config (object|function thing) //! Tries to find out which configuration the thing belongs to, if //! any. The thing can be e.g. a config or module object, a Tag object //! or a simple_tag callback. { if (RoxenModule mod = get_owning_module (thing)) return mod->my_configuration(); if (functionp (thing)) thing = function_object (thing); if (objectp (thing)) { if (thing->is_configuration) return thing; if (object parent = functionp (object_program (thing)) && function_object (object_program (thing))) { // This is mainly for finding tags defined in rxml.pike. if (parent->is_configuration) return parent; } } return 0; } #ifdef REQUEST_TRACE
acc6dd2000-08-15Martin Stjernholm static string trace_msg (RequestID id, string msg, string name)
b92a1c2000-08-14Martin Stjernholm {
acc6dd2000-08-15Martin Stjernholm  msg = html_decode_string (
b92a1c2000-08-14Martin Stjernholm  Parser.HTML()->_set_tag_callback (lambda (object p, string s) {return "";})-> finish (msg)->read());
acc6dd2000-08-15Martin Stjernholm  array(string) lines = msg / "\n"; if (lines[-1] == "") lines = lines[..sizeof (lines) - 2]; if (sizeof (lines)) report_debug ("%s%s%-40s %s\n", map (lines[..sizeof (lines) - 2], lambda (string s) { return sprintf ("%s%*s%s\n", id->misc->trace_id_prefix, id->misc->trace_level + 1, "", s); }) * "", id->misc->trace_id_prefix, sprintf ("%*s%s", id->misc->trace_level + 1, "", lines[-1]), name); } void trace_enter (RequestID id, string msg, object|function thing) { if (!id->misc->trace_level) {
f4c4d52000-08-27Martin Stjernholm  id->misc->trace_id_prefix = ({"%%", "##", "§§", "**", "@@", "$$", "¤¤"})[
acc6dd2000-08-15Martin Stjernholm  all_constants()->id_trace_level_rotate_counter++ % 7]; report_debug ("%s%s Request handled by: %O\n", id->misc->trace_id_prefix, id->misc->trace_id_prefix[..0], id->conf); }
b92a1c2000-08-14Martin Stjernholm  string name; if (thing) { name = get_modfullname (get_owning_module (thing)); if (name) name = "mod: " + html_decode_string ( Parser.HTML()->_set_tag_callback (lambda (object p, string s) {return "";})-> finish (name)->read()); else if (Configuration conf = get_owning_config (thing)) name = "conf: " + conf->query_name();
c7fb942000-09-05Martin Stjernholm  else
b92a1c2000-08-14Martin Stjernholm  name = sprintf ("obj: %O", thing); } else name = "";
acc6dd2000-08-15Martin Stjernholm  trace_msg (id, msg, name);
b92a1c2000-08-14Martin Stjernholm  id->misc->trace_level++; if(function(string,mixed ...:void) _trace_enter = [function(string,mixed ...:void)]([mapping(string:mixed)]id->misc)->trace_enter) _trace_enter (msg, thing); } void trace_leave (RequestID id, string desc) { if (id->misc->trace_level) id->misc->trace_level--;
acc6dd2000-08-15Martin Stjernholm  if (sizeof (desc)) trace_msg (id, desc, "");
b92a1c2000-08-14Martin Stjernholm  if(function(string:void) _trace_leave = [function(string:void)]([mapping(string:mixed)]id->misc)->trace_leave) _trace_leave (desc); }
c166222000-08-09Per Hedbor #endif