Added public files

Roughly added all public files. Probably missed some, though.
diff --git a/std/hook_provider.c b/std/hook_provider.c
new file mode 100644
index 0000000..00b8ca3
--- /dev/null
+++ b/std/hook_provider.c
@@ -0,0 +1,493 @@
+// MorgenGrauen MUDlib
+//
+// /std/hook_provider.c  - Hooksystem
+//
+// $Id: hook_provider.c 9453 2016-02-04 21:22:54Z Zesstra $
+
+#pragma strong_types
+#pragma save_types
+#pragma no_clone
+#pragma range_check
+#pragma pedantic
+
+#define NEED_PROTOTYPES
+#include <hook.h>
+#undef NEED_PROTOTYPES
+
+// get the object fur closure <cl> (where the code is!)
+#define GET_OBJECT(cl) get_type_info(cl,2)
+
+// Struct describing one hook consumer. <cl> will be called when the hook is
+// triggered. The lower <prio>, the earlier the consumer will be called.
+// <type> is a consumertype, e.g. surveyor, listener etc. (see hook.h)
+struct hook_entry_s {
+  closure cl;
+  int prio;
+  int endtime;
+  int type;
+};
+
+// Struct holding the consumers of one specific hook.
+// the value arrays are guarenteed to exist, but may be empty.
+struct hook_s {
+  struct hook_entry_s *surveyors;
+  struct hook_entry_s *hmods;
+  struct hook_entry_s *dmods;
+  struct hook_entry_s *listeners;
+};
+
+/* hook mapping
+   the list of all offered hooks in the following structure:
+   ([hookid: (<hook_s>), ...
+   )]
+*/
+private nosave mapping hookMapping=([]);
+
+protected void CleanHookMapping(int *hookids);
+
+// Debugging - ggf. ueberschreiben
+protected int h_dbg() {return 0;}
+
+void HookTestOffer(int id, int stat){
+  if(h_dbg()) {
+      offerHook(id,stat);
+  }
+}
+
+void HookTestTrigger(int id, mixed data){
+  if(h_dbg()) {
+      HookFlow(id,data);
+  }
+}
+
+// NOTE: if you have the closure, you can call the lfun, even if it is
+// private. Therefore access to this data should be restricted to
+// this_object().
+// These two functions should be used for debugging purposes.
+protected mapping HCopyHookMapping(){
+  return deep_copy(hookMapping);
+}
+
+protected mapping HCopyHookConsumers(int hookid){
+  if(member(hookMapping,hookid)) {
+      CleanHookMapping(({hookid}));
+      return deep_copy(hookMapping[hookid]);
+  }
+  return 0;
+}
+
+// Ggf. zum Ueberschreiben.
+int HConsumerTypeIsAllowed(int type, object consumer){
+  return 1;
+}
+
+int HPriorityIsAllowed(int prio, object consumer){
+  return 1;
+}
+
+// clean internal hook data structures of stale hook consumers.
+protected void CleanHookMapping(int *hookids){
+  // hooks enthaelt die aufzuraeumenden Hooks. Wenn kein Array -> alle Hooks
+  if (!pointerp(hookids))
+    hookids=m_indices(hookMapping);
+
+  foreach(int hookid : hookids) { // alle Hooks
+    struct hook_s hooks = hookMapping[hookid];
+    if (!structp(hooks))
+      continue;
+    // ueber alle Consumertypen laufen
+    foreach (string consumertype: H_CONSUMERNAMES)
+    {
+      // Yeah - compute struct lookup at runtime... ;-)
+      struct hook_entry_s *consumers = hooks->(consumertype);
+      // Hookeintraege / Consumer
+      foreach(struct hook_entry_s h : &consumers) {
+        // alle abgelaufenen Eintraege oder solche mit zerstoerten Objekten
+        // nullen
+        if (!h->cl || h->endtime < time() )
+            h = 0;
+      }
+      // 0 noch rauswerfen.
+      hooks->(consumertype) -= ({0});
+    }
+  }
+}
+
+protected void offerHook(int hookid, int offerstate)
+{
+  H_DMSG(sprintf("offerHook hookid %d offerstate %d\n",hookid,offerstate));
+  if (hookid>0)
+  {
+      if (offerstate) {
+          if (!member(hookMapping,hookid)) {
+              struct hook_s hook = (<hook_s>
+                  surveyors: ({}),
+                  hmods: ({}),
+                  dmods: ({}),
+                  listeners: ({}) );
+              hookMapping[hookid] = hook;
+          }
+      }
+      else {
+          if (member(hookMapping,hookid)) {
+            m_delete(hookMapping,hookid);
+          }
+      }
+  }
+  H_DMSG(sprintf("  result %O\n",hookMapping));
+}
+
+// hookConsumerInfo() liefert Array von hook_entry_s zurueck. D.h. bei Abfrage
+// von Objekten alle Closures dieses Objekts und jede davon erzeugt ein
+// Element hook_entry_s im Ergebnisarray. Bei Abfrage von Closures hat das
+// Array immer genau 1 oder kein Element.
+// WARNING: whoever has a hook_entry_s can change/delete the hook!
+//          NEVER return the original to an external caller!
+// NOTE: whoever has the cl from hook_entry_s can call it, even if the lfun
+//       is private (and this object the only one knowing it).
+protected mixed * hookConsumerInfo(int hookid, object|closure consumer)
+{
+  closure filter_cl;
+
+  if (!member(hookMapping,hookid))
+    return ({});
+
+  // Closure zum Filtern bestimmen - je nachdem, was gesucht wird.
+  if (closurep(consumer))
+  {
+    filter_cl = function int (struct hook_entry_s h)
+                { return h->cl == consumer
+                         && h->endtime >= time(); };
+  }
+  else if (objectp(consumer))
+  {
+    filter_cl = function int (struct hook_entry_s h)
+                { return GET_OBJECT(h->cl) == consumer
+                         && h->endtime >= time(); };
+  }
+  else
+  {
+    return ({});
+  }
+
+  struct hook_s hook = hookMapping[hookid];
+  struct hook_entry_s *result = ({});
+  foreach (string consumertype: H_CONSUMERNAMES )
+  {
+    result += filter(hook->(consumertype), filter_cl);
+  }
+  return result;
+}
+
+int HIsHookConsumer(int hookid, mixed consumer) {
+  return sizeof(hookConsumerInfo(hookid,consumer)) != 0;
+}
+
+int* HListHooks() {
+  return m_indices(hookMapping);
+}
+
+int HUnregisterFromHook(int hookid, mixed consumer) {
+
+  H_DMSG(sprintf("HUnregisterFromHook hookid %d consumer %O\n",hookid,consumer));
+  if (objectp(consumer))
+    consumer = symbol_function("HookCallback", consumer);
+  if (!closurep(consumer))
+    return 0;
+
+  struct hook_entry_s *info = hookConsumerInfo(hookid,consumer);
+
+  // it should never happen that a closure is registered more than once, i.e.
+  // the result contains more than one element.
+  if (sizeof(info)) {
+      struct hook_entry_s h = info[0];
+      h->cl = 0;
+      H_DMSG(sprintf("  result %O\n", hookMapping));
+      // the now invalid h will be cleaned up later.
+      return 1;
+  }
+  return 0;
+}
+
+// surveyors are asked for registration permittance
+protected int askSurveyorsForRegistrationAllowance(
+                  struct hook_entry_s *surveyors, object consumer,int hookid,
+                  int hookprio,int consumertype)
+{
+  H_DMSG(sprintf("askSurveyorsForRegistrationAllowance surveyors %O, "
+        "consumer %O, hookid %d, hookprio %d, consumertype %d\n",
+        surveyors,consumer,hookid,hookprio,consumertype));
+
+  foreach(struct hook_entry_s surveyor : surveyors) {
+    if (closurep(surveyor->cl) && surveyor->endtime >= time())
+    {
+      // surveyor hook gueltig.
+      object sob = GET_OBJECT(surveyor->cl);
+      if (!sob->HookRegistrationCallback(consumer, hookid,
+                        this_object(), hookprio, consumertype))
+        return 0;
+    }
+  }
+  return 1;
+}
+
+int HRegisterToHook(int hookid, mixed consumer, int hookprio,
+                       int consumertype, int timeInSeconds) {
+  int ret, regtime;
+
+  if (!closurep(consumer) && !objectp(consumer))
+    raise_error(sprintf("Wrong argument %.50O to HRegisterToHook(): consumer "
+          "must be closure or object.\n",consumer));
+
+  if (!member(hookMapping, hookid))
+    return -1;
+
+  if (objectp(consumer)) {
+    consumer = symbol_function("HookCallback", consumer);
+    if (!closurep(consumer))
+      return -2;
+  }
+
+  if (timeInSeconds > 0) {
+      regtime=time() + timeInSeconds;
+  }
+  else {
+      regtime=__INT_MAX__;
+  }
+
+  H_DMSG(sprintf("HRegisterToHook hookid %d consumer %O\n hookprio %d "
+        "consumertype %d\n",hookid,consumer,hookprio,consumertype));
+
+  CleanHookMapping(({hookid})); // entfernt ungueltige/abgelaufene Eintraege
+
+  // nur einmal pro closure registrieren!
+  if (HIsHookConsumer(hookid, consumer))
+    return -3;
+
+  // Consumertyp erlaubt?
+  if (H_CONSUMERCHECK(consumertype) == -1
+      || !HConsumerTypeIsAllowed(consumertype,GET_OBJECT(consumer)))
+    return -4;
+
+  // Prioritaet erlaubt?
+  if (H_HOOK_VALIDPRIO(hookprio) == -1
+      || !HPriorityIsAllowed(hookprio, GET_OBJECT(consumer)))
+    return -5;
+
+  struct hook_s hook = hookMapping[hookid];
+
+  // Und surveyors erlauben die Registierung?
+  if (!askSurveyorsForRegistrationAllowance(hook->surveyors,
+                    GET_OBJECT(consumer),hookid,
+                    hookprio,consumertype))
+    return -6;
+
+  string ctypename = H_CONSUMERNAMES[consumertype];
+
+  // get the consumer array
+  struct hook_entry_s *consumers = hook->(ctypename);
+
+  // assemble new hook consumer struct
+  struct hook_entry_s newconsumer = (<hook_entry_s>
+                      cl : consumer,
+                      prio : hookprio,
+                      endtime : regtime,
+                      type : consumertype );
+
+  // consumers enthaelt die Hookeintraege
+  if (sizeof(consumers) < MAX_HOOK_COUNTS[consumertype]) {
+    // max. Anzahl an Eintraegen fuer diesen Typ noch nicht
+    // erreicht, direkt anhaengen.
+    consumers += ({ newconsumer });
+    hook->(ctypename) = consumers;
+    ret=1;
+  }
+  else {
+    // gibt es einen Eintrag mit hoeherem Priowert (niedrigere
+    // Prioritaet), den man ersetzen koennte?
+    // Das Array ist sortiert, mit hoechsten Priowerten am
+    // Ende. Ersetzt werden soll der Eintrag mit dem hoechsten
+    // Zahlenwert, falls der neue Eintrag einen niedrigeren Wert
+    // hat, d.h. es muss nur er letzte Consumer im Array geprueft werden.
+    // Pruefung auf Closureexistenz, falls der Surveyor Objekte
+    // zerstoert (hat)...
+    struct hook_entry_s oh = consumers[<1];
+    if (!oh->cl || oh->prio > newconsumer->prio) {
+      // Found superseedable entry - replace it, but inform the object.
+      H_DMSG("Found superseedable entry\n");
+      consumers[<1] = newconsumer;
+      GET_OBJECT(oh->cl)->superseededHook(hookid, this_object());
+      ret = 1;
+      // nicht noetig, consumers wieder in sein hook_s zu haenngen wegen Array
+      // -> Referenz
+    }
+  }
+
+  // wenn ein Eintrag hinzugefuegt wurde, muss neu sortiert werden
+  if (ret) {
+    hook->(ctypename) = sort_array(consumers,
+        function int (struct hook_entry_s a, struct hook_entry_s b) {
+            return a->prio > b->prio; } );
+  }
+
+  H_DMSG(sprintf("  result %O\n",hookMapping));
+
+  // -7, wenn kein Eintrag mehr frei / zuviele Hooks
+  return (ret > 0 ? 1 : -7);
+}
+
+// Conveniences wrapper for simple listener hooks
+int HRegisterListener(int hookid, mixed consumer)
+{
+  return HRegisterToHook(hookid, consumer, H_HOOK_OTHERPRIO(2), H_LISTENER, 0);
+}
+
+// Cnveniences wrapper for simple modificator hooks
+int HRegisterModifier(int hookid, mixed consumer)
+{
+  return HRegisterToHook(hookid, consumer, H_HOOK_OTHERPRIO(2),
+                         H_HOOK_MODIFICATOR, 0);
+}
+
+// surveyors are asked for cancellation permittance
+protected int askSurveyorsForCancelAllowance(mixed surveyors,
+  object modifiyingOb,mixed data,int hookid,int prio,object hookOb){
+
+  foreach(struct hook_entry_s surveyor : surveyors) {
+    if (closurep(surveyor->cl) && surveyor->endtime >= time())
+    {
+      // surveyor hook gueltig.
+      object sob = GET_OBJECT(surveyor->cl);
+      if (!sob->HookCancelAllowanceCallback(modifiyingOb, hookid,
+                        hookOb, prio, data))
+        return 0;
+    }
+  }
+  return 1;
+}
+
+// surveyors are asked for data change permittance
+protected int askSurveyorsForModificationAllowance(mixed surveyors,
+  object modifiyingOb,mixed data,int hookid,int prio,object hookOb){
+
+  foreach(struct hook_entry_s surveyor : surveyors) {
+    if (closurep(surveyor->cl) && surveyor->endtime >= time())
+    {
+      // surveyor hook gueltig.
+      object sob = GET_OBJECT(surveyor->cl);
+      if (!sob->HookModificationAllowanceCallback(modifiyingOb,
+                        hookid, hookOb, prio, data))
+        return 0;
+    }
+  }
+  return 1;
+}
+
+protected mixed HookFlow(int hookid, mixed hookdata){
+  mixed tmp, ret;
+
+  ret=({H_NO_MOD,hookdata});
+
+  H_DMSG(sprintf("HookFlow hookid %d hookdata %O\n",hookid,hookdata));
+
+  if (!member(hookMapping, hookid))
+    return ret;
+
+  struct hook_s hook = hookMapping[hookid];
+
+  // notify surveyors
+  foreach(struct hook_entry_s h : hook->surveyors) {
+    if (closurep(h->cl) && h->endtime >= time())
+    {
+      // Hook gueltig
+      tmp = funcall(h->cl, this_object(), hookid, ret[H_RETDATA]);
+      if(tmp[H_RETCODE]==H_CANCELLED) {
+        ret[H_RETCODE]=H_CANCELLED;
+        return ret;  // und weg...
+      }
+      else if(tmp[H_RETCODE]==H_ALTERED){
+        ret[H_RETCODE]=H_ALTERED;
+        ret[H_RETDATA]=tmp[H_RETDATA];
+      }
+    }
+    // ungueltige/abgelaufene Eintraege -> Aufraeumen, aber nicht jetzt.
+    else if (find_call_out(#'CleanHookMapping) == -1) {
+      call_out(#'CleanHookMapping, 0, ({hookid}));
+    }
+  } // surveyors fertig
+
+  // notify hmods
+  foreach(struct hook_entry_s h : hook->hmods) {
+    if (closurep(h->cl) && h->endtime >= time())
+    {
+      // Hook gueltig
+      tmp = funcall(h->cl, this_object(), hookid, ret[H_RETDATA]);
+      if(tmp[H_RETCODE]==H_CANCELLED) {
+        // ask allowance in surveyors
+        if(h->cl &&
+           askSurveyorsForCancelAllowance(hook->surveyors,
+              GET_OBJECT(h->cl), hookdata, hookid,
+              h->prio, this_object()))
+        {
+            ret[H_RETCODE] = H_CANCELLED;
+            return ret; // und raus...
+        }
+      }
+      else if(tmp[H_RETCODE]==H_ALTERED) {
+        // ask allowance in surveyors
+        if(h->cl &&
+           askSurveyorsForModificationAllowance(hook->surveyors,
+              GET_OBJECT(h->cl),hookdata, hookid,
+              h->prio,this_object()))
+        {
+            ret[H_RETCODE] = H_ALTERED;
+            ret[H_RETDATA] = tmp[H_RETDATA];
+        }
+      }
+    }
+    // ungueltige/abgelaufene Eintraege -> Aufraeumen, aber nicht jetzt.
+    else if (find_call_out(#'CleanHookMapping) == -1) {
+      call_out(#'CleanHookMapping, 0, ({hookid}));
+    }
+  } // hmods fertig
+
+  // notify dmods
+  foreach(struct hook_entry_s h : hook->dmods) {
+    if (closurep(h->cl) && h->endtime >= time())
+    {
+      // Hook gueltig
+      tmp = funcall(h->cl, this_object(), hookid, ret[H_RETDATA]);
+      if(tmp[H_RETCODE]==H_ALTERED) {
+        // ask allowance in surveyors
+        if (h->cl &&
+            askSurveyorsForModificationAllowance(hook->surveyors,
+              GET_OBJECT(h->cl),hookdata, hookid,
+              h->prio,this_object()))
+        {
+            ret[H_RETCODE] = H_ALTERED;
+            ret[H_RETDATA] = tmp[H_RETDATA];
+        }
+      }
+    }
+    // ungueltige/abgelaufene Eintraege -> Aufraeumen, aber nicht jetzt.
+    else if (find_call_out(#'CleanHookMapping) == -1) {
+      call_out(#'CleanHookMapping, 0, ({hookid}));
+    }
+  } // dmods fertig
+
+  // notify listener
+  foreach(struct hook_entry_s h : hook->listeners) {
+    if (closurep(h->cl) && h->endtime >= time())
+    {
+      // Hook gueltig
+      funcall(h->cl, this_object(), hookid, ret[H_RETDATA]);
+    }
+    // ungueltige/abgelaufene Eintraege -> Aufraeumen, aber nicht jetzt.
+    else if (find_call_out(#'CleanHookMapping) == -1) {
+      call_out(#'CleanHookMapping, 0, ({hookid}));
+    }
+  } // listener fertig
+
+  return ret;
+}
+