Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/std/util/cidr.c b/std/util/cidr.c
new file mode 100644
index 0000000..85a00e5
--- /dev/null
+++ b/std/util/cidr.c
@@ -0,0 +1,26 @@
+// MorgenGrauen MUDlib
+/** \file /std/util/cidr.c
+* Funktionen zur Interpretation und Umrechnung von IP-Adressen in CIDR-Notation.
+* \author Zesstra
+* \date 05.02.2010
+* \version $Id$
+*/
+/* Changelog:
+*/
+#pragma strong_types
+#pragma save_types
+#pragma no_clone
+#pragma no_shadow
+#pragma pedantic
+#pragma range_check
+
+// Never do this at home. ;-)
+// Der Hintergrund ist, dass der Master moeglichst wenig Code von ausserhalb
+// /secure/ erben/inkludieren sollte, ich aber nur an einer Stelle Aenderungen
+// vornehmen moechte...
+#define private public
+#include "/secure/master/cidr.c"
+#undef private
+
+//string IPv4_test(string addr) {return (IPv4_int2addr(IPv4_addr2int(addr)));}
+
diff --git a/std/util/ex.c b/std/util/ex.c
new file mode 100644
index 0000000..eae9e27
--- /dev/null
+++ b/std/util/ex.c
@@ -0,0 +1,293 @@
+// MorgenGrauen MUDlib
+//
+// util/ex.c -- ex compatible editor
+//
+// $Id: ex.c 9142 2015-02-04 22:17:29Z Zesstra $
+
+#pragma strong_types
+#pragma save_types
+#pragma pedantic
+#pragma range_check
+#pragma no_clone
+
+inherit "/std/util/input";
+
+private nosave mapping ctrl = ([]);
+private nosave mixed buf;
+
+#include <sys_debug.h>
+#undef ARGS
+#include <wizlevels.h>
+#include <player.h>
+
+#define MODE 0
+# define CMD 0
+# define INP 1
+#define TEXT 1
+#define LINE 2
+#define FUNC 3
+#define ARGS 4
+#define FLAG 5
+# define NUM 1
+#define CHG 6
+
+#define YANK "@YANK"
+
+int evaluate(string in);
+
+varargs int error(string msg, string arg)
+{
+ if(stringp(arg)) write(arg+": "+msg+"\n");
+ else write(msg+"\n");
+}
+
+string substitute(string s, string regex, string n, string extra)
+{
+ mixed del; int i;
+ if((i = sizeof(del = regexplode(s, regex))) < 2) return s;
+ if(member(extra, 'g') == -1) i = 1;
+ else i -= 2;
+ while(i>0) {
+ del[i] = n;
+ i -= 2;
+ }
+ return implode(del, "");
+}
+
+// saveText() -- save edited text
+//
+int saveText()
+{
+ string text;
+ text = implode(ctrl[buf][TEXT][1..], "\n")+"\n";
+ error(sprintf("%O, %d Zeilen, %d Zeichen",
+ buf ? buf : "", sizeof(ctrl[buf][TEXT])-1,
+ sizeof(text)));
+ if(ctrl[buf][FUNC]) apply(ctrl[buf][FUNC], ctrl[buf][ARGS], text);
+ ctrl = m_copy_delete(ctrl, buf);
+ ctrl = m_copy_delete(ctrl, buf+"!");
+ buf = 0;
+ return 1;
+}
+
+// cmdPrompt() -- create command prompt
+//
+string cmdPrompt(int mode, mixed text, int line, int maxl)
+{
+ return ":";
+}
+
+// inputPrompt() -- create input prompt
+//
+string inputPrompt()
+{
+ if(ctrl[buf][FLAG] & NUM) return sprintf("[%02d] ", ctrl[buf][LINE]);
+ return "";
+}
+
+string AddNum(string s)
+{
+ string r;
+ r = inputPrompt()+s;
+ ctrl[buf][LINE]++;
+ return r;
+}
+
+void showLines(int from, int to)
+{
+ write(implode(map(ctrl[buf][TEXT][from..to], #'AddNum), "\n")+"\n");
+ ctrl[buf][LINE] = from;
+}
+
+// commandMode() -- handle commands
+//
+int commandMode(string in)
+{
+ int from, to, swap;
+ string cmd;
+
+ if(!in) return 0;
+ if(in[0..1] == "se") {
+ ctrl[buf][FLAG] ^= NUM;
+ return 0;
+ }
+
+ if(sscanf(in, "%d,%d%s", from, to, cmd) != 3)
+ if(sscanf(in, "%d%s", from, cmd) != 2)
+ if(!stringp(in)) return error("Kein Editorkommando", in);
+ else { cmd = in; from = to = ctrl[buf][LINE]; }
+ else to = from;
+
+ if(from < 0) from = sizeof(ctrl[buf][TEXT])-1+from;
+ if(to < 1) to = sizeof(ctrl[buf][TEXT])-1+to;
+ if(to && to < from) return error("Erste Adresse groesser als die Zweite");
+ if(from) ctrl[buf][LINE] = from;
+ if(from > sizeof(ctrl[buf][TEXT])-1 ||
+ to > sizeof(ctrl[buf][TEXT])-1)
+ return error("Nicht so viele Zeilen im Speicher");
+ if(!to) to = from;
+ switch(cmd[0])
+ {
+ case 'h':
+ write("ex: Kommandohilfe\n\n"
+ "Alle Kommandos funktionieren nach folgendem Prinzip:\n"
+ "Adresse Kommando Argumente\n"
+ "Adressen werden gebildet durch: ZeileVon,ZeileBis\n"
+ "(ZeileBis kann weggelassen werden, samt Komma)\n"
+ "Kommandos:\n"
+ " q,x -- Editor verlassen\n"
+ " r -- Datei einfuegen\n"
+ " r<datei>\n"
+ " a -- Text hinter der aktuellen Zeile einfuegen\n"
+ " i -- Text vor der aktuellen Zeile einfuegen\n"
+ " d -- Zeilen loeschen\n"
+ " y -- Zeilen zwischenspeichern\n"
+ " pu -- Zwischengespeicherte Zeilen einfuegen\n"
+ " s -- Substitution von Text in Zeilen\n"
+ " s/AlterText/NeuerText/\n"
+ " p,l -- Zeilen anzeigen\n"
+ " z -- Eine Seite anzeigen\n");
+ break;
+ case 'q':
+ if(ctrl[buf][CHG])
+ if(!(sizeof(cmd) > 1 && cmd[1]=='!'))
+ return error("Datei wurde geaendert! Abbrechen mit q!");
+ else ctrl[buf] = ctrl[buf+"!"];
+ case 'x':
+ if(saveText()) return 1;
+ case 'r':
+ if(!IS_WIZARD(this_player()))
+ return error("Kommando gesperrt", cmd[0..0]);
+ if(file_size(cmd[1..]) < 0)
+ return error("Datei nicht gefunden", "\""+cmd[1..]+"\"");
+ ctrl[buf][TEXT] = ctrl[buf][TEXT][0..from]
+ + explode(read_file(cmd[1..]), "\n")
+ + ctrl[buf][TEXT][(from == to ? to+1 : to)..];
+ ctrl[buf][CHG] = 1;
+ break;
+ case 'a':
+ ctrl[buf][MODE] = INP;
+ write("Texteingabe: (. beendet zum Kommandomodus, ** beendet ganz)\n");
+ input(#'inputPrompt, 0, #'evaluate);
+ ctrl[buf][CHG] = 1;
+ return 1;
+ case 'i':
+ ctrl[buf][MODE] = INP;
+ ctrl[buf][LINE]--;
+ write("Texteingabe: (. beendet zum Kommandomodus, ** beendet ganz)\n");
+ input(#'inputPrompt, 0, #'evaluate);
+ ctrl[buf][CHG] = 1;
+ return 1;
+ case 'd':
+ ctrl[buf][TEXT][from..to] = ({});
+ ctrl[buf][CHG] = 1;
+ break;
+ case 'y':
+ ctrl[YANK] = ctrl[buf][TEXT][from..to];
+ if(to - from) error(to-from+1+" Zeilen gespeichert");
+ break;
+ case 's':
+ {
+ mixed reg, new, extra, scmd;
+ if(sizeof(scmd = old_explode(cmd[1..], cmd[1..1])) < 2)
+ return error("Substitution fehlgeschlagen");
+ reg = scmd[0]; new = scmd[1];
+ if(sizeof(scmd) > 2) extra = scmd[2];
+ else extra = "";
+ ctrl[buf][TEXT][from..to] = map(ctrl[buf][TEXT][from..to],
+ #'substitute,
+ reg, new, extra);
+ showLines(from, to);
+ ctrl[buf][CHG] = 1;
+ break;
+ }
+ case 'z':
+ showLines(ctrl[buf][LINE],
+ ctrl[buf][LINE]+this_player()->QueryProp(P_SCREENSIZE));
+ ctrl[buf][LINE] += this_player()->QueryProp(P_SCREENSIZE);
+ break;
+ case 'p':
+ if(sizeof(cmd) > 1 && cmd[1] == 'u')
+ {
+ if(!pointerp(ctrl[YANK])) return error("Keine Zeilen im Speicher");
+ if(from >= ctrl[buf][LINE]) ctrl[buf][TEXT] += ctrl[YANK];
+ else
+ ctrl[buf][TEXT][0..from] + ctrl[YANK] + ctrl[buf][TEXT][from+1..];
+ ctrl[buf][LINE] += sizeof(ctrl[YANK]);
+ ctrl[YANK] = 0;
+ showLines(ctrl[buf][LINE], ctrl[buf][LINE]);
+ break;
+ }
+ case 'l':
+ default:
+ if(!from)
+ {
+ error("Kein Editorkommando", sprintf("%c", cmd[0]));
+ return 0;
+ }
+ showLines(from, to);
+ }
+ input(#'cmdPrompt, 0, #'evaluate);
+ return 1;
+}
+
+// inputMode() -- handle input mode commands
+//
+int inputMode(string in)
+{
+ switch(in)
+ {
+ case ".":
+ ctrl[buf][MODE] = CMD;
+ ctrl[buf][LINE]--;
+ input(#'cmdPrompt, 0, #'evaluate);
+ break;
+ case "**":
+ return saveText();
+ default:
+ if(!in) /* do nothing now */;
+ if(ctrl[buf][LINE] < sizeof(ctrl[buf][TEXT])-1)
+ ctrl[buf][TEXT] = ctrl[buf][TEXT][0..ctrl[buf][LINE]-1] + ({ in })
+ + ctrl[buf][TEXT][ctrl[buf][LINE]..];
+ else ctrl[buf][TEXT] += ({ in });
+ ctrl[buf][LINE]++;
+ input(#'inputPrompt, 0, #'evaluate);
+ break;
+ }
+ return 1;
+}
+
+// evaluate() -- evaluate input (in) in context (ctrl[buf])
+//
+int evaluate(string in)
+{
+ switch(ctrl[buf][MODE])
+ {
+ case INP: return inputMode(in);
+ case CMD: return commandMode(in);
+ default : return 0;
+ }
+}
+
+void StartEX(string in, mixed c)
+{
+ if(!in || in == "j" || in == "J") ctrl[buf] = c;
+ else if(in && (in != "n" || in != "N"))
+ return 0;
+ ctrl[buf+"!"] = ctrl[buf];
+ input(#'cmdPrompt, 0, #'evaluate);
+}
+
+varargs int ex(mixed text, closure func, mixed fargs, string buffer)
+{
+ int c, l;
+ mixed ct;
+ if(!text) text = "";
+ c = sizeof(text);
+ l = sizeof(text = explode(text, "\n")) - 1;
+ ct = ({ CMD, text, 0, func, fargs, 0, 0});
+ if(!ctrl[buffer]) StartEX(0, ct);
+ else input(sprintf("Es existiert bereits Text! Verwerfen? [j]"),
+ 0, #'StartEX, ct);
+ return 1;
+}
diff --git a/std/util/executer.c b/std/util/executer.c
new file mode 100644
index 0000000..4e0f707
--- /dev/null
+++ b/std/util/executer.c
@@ -0,0 +1,39 @@
+// MorgenGrauen MUDlib
+//
+// utils/executer.c - Helfer zum Ausfuehren vom Kram
+//
+// $Id: skills.c 6673 2008-01-05 20:57:43Z Zesstra $
+#pragma strict_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+protected mixed execute_anything(mixed fun, varargs mixed args)
+{
+ if ( closurep(fun) && objectp(query_closure_object(fun)) )
+ return apply(fun, args);
+
+ if (stringp(fun))
+ return call_other(this_object(), fun, args...);
+
+ if ( pointerp(fun) && sizeof(fun)==2 )
+ {
+ object ob;
+ if (sizeof(fun)>2)
+ raise_error(sprintf("execute_anything(): first argument may only "
+ "have 2 elements if array.\n"));
+
+ if ( stringp(fun[0]) )
+ ob=find_object(fun[0]);
+ else
+ ob=fun[0];
+
+ if ( !objectp(ob) || !stringp(fun[1]) )
+ return 0;
+
+ return call_other(ob, fun[1], args...);
+ }
+ return 0;
+}
+
diff --git a/std/util/input.c b/std/util/input.c
new file mode 100644
index 0000000..e65bc84
--- /dev/null
+++ b/std/util/input.c
@@ -0,0 +1,31 @@
+// MorgenGrauen MUDlib
+//
+// util/input.c -- generic input handling
+//
+// $Id: input.c 8349 2013-02-04 21:15:28Z Zesstra $
+
+#include <input_to.h>
+
+#pragma strong_types
+#pragma save_types
+#pragma pedantic
+#pragma range_check
+#pragma no_clone
+
+varargs void input(mixed prompt, mixed pargs, mixed ctrl, mixed ctrlargs)
+{
+ mixed prompttext;
+ if(closurep(prompt))
+ prompttext = apply(prompt, pointerp(pargs) ? pargs : ({}));
+ else prompttext = prompt;
+ if (!stringp(prompttext)) prompttext="";
+ input_to("done", INPUT_PROMPT, prompttext, prompt, pargs, ctrl, ctrlargs);
+}
+
+void done(string in, mixed prompt, mixed pargs, mixed ctrl, mixed ctrlargs)
+{
+ if(closurep(ctrl) &&
+ apply(ctrl, ({ in }) + (pointerp(ctrlargs) ? ctrlargs : ({}))))
+ return;
+ input(prompt, pargs, ctrl, ctrlargs);
+}
diff --git a/std/util/pager.c b/std/util/pager.c
new file mode 100644
index 0000000..9d71b85
--- /dev/null
+++ b/std/util/pager.c
@@ -0,0 +1,142 @@
+// MorgenGrauen MUDlib
+//
+// util/pager.c -- generic pager
+//
+// $Id: pager.c 8755 2014-04-26 13:13:40Z Zesstra $
+
+#pragma strong_types
+#pragma save_types
+#pragma pedantic
+#pragma range_check
+#pragma no_clone
+
+inherit "/std/util/input";
+
+#include <pager.h>
+#include <sys_debug.h>
+#include <wizlevels.h>
+
+string prompt(mixed pinfo, string add)
+{
+ return sprintf(MSG_PROMPT+"%s", stringp(add)?add:"");
+}
+
+string fread(mixed pinfo, int begin, int c)
+{
+ if(begin > pinfo[MAXL] || begin < 1) return 0;
+ if(pinfo[FILE]) return read_file(pinfo[TEXT], begin, c);
+ else
+ {
+ int start, end, l, x;
+
+ if(member(pinfo[JUNK], begin))
+ {
+ start = pinfo[JUNK][begin];
+ if(!(end = pinfo[JUNK][begin+c]))
+ end = sizeof(pinfo[TEXT]);
+ else end--;
+ return pinfo[TEXT][start..end];
+ }
+ return 0;
+ }
+}
+
+mixed call(closure ctrl, mixed ctrlargs)
+{
+ if (!ctrl||!closurep(ctrl)) return 0;
+ if(!pointerp(ctrlargs)) return funcall(ctrl);
+ return apply(ctrl, ctrlargs);
+}
+
+
+varargs int eval_command(mixed in, mixed pinfo)
+{
+ string cprompt, tmp;
+ cprompt = "";
+ if(in == "q" || in == "x")
+ {
+ if(closurep(pinfo[CTRL])) apply(pinfo[CTRL], pinfo[CARG]);
+ return 1;
+ }
+ else
+ if(!in || (stringp(in) && !sizeof(in))) pinfo[CURL] += pinfo[PAGE];
+ else if(in != -1) return 0;
+
+ if(pinfo[CURL] >= pinfo[MAXL])
+ return (call(pinfo[CTRL], pinfo[CARG]), 1);
+ if(pinfo[CURL] <= 0) pinfo[CURL] = 1;
+ if(pinfo[CURL] == 1) cprompt = MSG_TOP;
+ if(pinfo[CURL] + pinfo[PAGE] >= pinfo[MAXL]) cprompt = MSG_BOTTOM;
+ if(!tmp = fread(pinfo, pinfo[CURL], pinfo[PAGE]))
+ return 0; /* (write(MSG_OOPS+"\n"), 0); */
+ if (query_once_interactive(this_object()))
+ tell_object(this_object(), tmp);
+ else write(tmp);
+ if(!(pinfo[FLAG] & E_PROMPT) &&
+ (pinfo[CURL] + pinfo[PAGE] >= pinfo[MAXL] || !pinfo[PAGE]))
+ return (call(pinfo[CTRL], pinfo[CARG]), 1);
+ if(!(pinfo[FLAG] & E_CAT) &&
+ (pinfo[MAXL] > pinfo[PAGE] || (pinfo[FLAG] & E_PROMPT)))
+ input(#'prompt, ({ pinfo, cprompt }), #'eval_command, ({ pinfo }));
+ return 1;
+}
+
+varargs public void More(string txt, int file,
+ mixed ctrl, mixed ctrlargs,
+ int flags)
+{
+ int j;
+ mixed tmp, pinfo;
+ if(!txt) return call(ctrl, ctrlargs);
+ // TEXT, FILE, CURL, MAXL, REGX, PAGE, CTRL, CARG
+ pinfo = ({ txt, file, 1, 1, 20, 0, ctrl, ctrlargs, flags });
+
+ if (pinfo[FILE])
+ {
+ if (file_size(pinfo[TEXT])<50000)
+ {
+ pinfo[TEXT]=read_file(pinfo[TEXT]);
+ if (!pinfo[TEXT])
+ {
+ call(ctrl, ctrlargs);
+ return;
+ }
+ pinfo[FILE]=0;
+ }
+ else if (file_size(pinfo[TEXT])>1048576)
+ {
+ tell_object(this_player()||this_object(),break_string(sprintf(
+ "Die Datei '%s' kann nicht angezeigt werden, da "
+ "sie groesser als 1 MB ist. %s",pinfo[TEXT],
+ IS_LEARNER(this_player()||this_object())?"":"Bitte verstaendige "
+ "diesbezueglich umgehend einen Magier."),78));
+ call(ctrl,ctrlargs);
+ return;
+ }
+ }
+
+ if(!pinfo[FILE] && pinfo[TEXT][<1..<1] != "\n") pinfo[TEXT] += "\n";
+ pinfo += ({ ([1:0]) });
+ if(!pinfo[FILE])
+ while((j = strstr(pinfo[TEXT], "\n", j+1)) != -1)
+ pinfo[JUNK][++pinfo[MAXL]] = j+1;
+ else
+ while(tmp = read_file(pinfo[TEXT], pinfo[MAXL], MAX_LINE_READ))
+ pinfo[MAXL] += sizeof(explode(tmp, "\n"))+1;
+ pinfo[PAGE] = PAGELENGTH;
+ if(!pinfo[PAGE]) pinfo[FLAG] |= E_CAT;
+ if ((this_interactive() && (j=(int)this_interactive()->QueryProp(P_MORE_FLAGS))) ||
+ (this_player() && interactive(this_player()) &&
+ (j=(int)this_player()->QueryProp(P_MORE_FLAGS))))
+ pinfo[FLAG] |= j;
+
+ pinfo[CURL] = 1;
+ eval_command(-1, pinfo);
+ return;
+}
+
+
+
+
+
+
diff --git a/std/util/pl_iterator.c b/std/util/pl_iterator.c
new file mode 100644
index 0000000..555a75e
--- /dev/null
+++ b/std/util/pl_iterator.c
@@ -0,0 +1,53 @@
+// MorgenGrauen MUDlib
+/** \file /file.c
+* Kurzbeschreibung.
+* Langbeschreibung...
+* \author <Autor>
+* \date <date>
+* \version $Id$
+*/
+/* Changelog:
+*/
+#pragma strong_types, save_types, rtt_checks
+#pragma no_clone, no_shadow
+#pragma pedantic, range_check
+#pragma warn_deprecated
+
+private void check_all_player(mapping allplayer, closure check_cl,
+ closure finish_cl, int res,
+ varargs mixed extra)
+{
+ // offenbar fertig mit allen Spielern, Aufrufer informieren.
+ if (!sizeof(allplayer))
+ {
+ funcall(finish_cl, extra...);
+ return;
+ }
+
+ string dir=m_indices(allplayer)[0];
+ string *pls=allplayer[dir];
+ foreach(string pl: &pls)
+ {
+ if (get_eval_cost() < res)
+ break; // spaeter weitermachen
+ catch(funcall(check_cl, pl, extra...) ; publish);
+ pl = 0;
+ }
+ pls-=({0});
+ allplayer[dir] = pls;
+
+ if (!sizeof(allplayer[dir]))
+ m_delete(allplayer,dir);
+
+ call_out(#'check_all_player,2, allplayer, check_cl, finish_cl, res, extra...);
+}
+
+protected int start_player_check(closure check_cl, closure finish_cl, int res,
+ varargs mixed extra)
+{
+ res ||= 1250000;
+ mapping allplayer=(mapping)master()->get_all_players();
+ call_out(#'check_all_player,2, allplayer, check_cl, finish_cl, res, extra...);
+ return 1;
+}
+
diff --git a/std/util/rand-glfsr.c b/std/util/rand-glfsr.c
new file mode 100644
index 0000000..8bd624c
--- /dev/null
+++ b/std/util/rand-glfsr.c
@@ -0,0 +1,155 @@
+/* Dieses File implementiert einen Pseudo-Zufallszahlengenerator mit einem
+ * Linear Feedback Shift Register in der Galois-Variante.
+ * Dieses PRNG ist schlechter und viel ineffizienter als der im Driver
+ * eingebaute.
+ * Die einzige sinnvolle Anwendung ist, wenn man aus irgendeinem Grund das
+ * seed selber waehlen muss, damit man die Sequenz von Pseudozufall immer
+ * wieder reproduzieren kann.
+ *
+ * Das Seed von der Blueprint wird vermutlich staendig veraendert (d.h.
+ * verlasst euch nicht drauf, dass es konstant bleibt), wollt ihr eine
+ * 'private' Instanz mit eurem Seed, clont das Objekt (aber verliert den Clone
+ * nicht).
+ *
+ * Es wird standardmaessig ein Polynom fuer eine Periodenlaenge von 2^32 - 1
+ * verwendet.
+ *
+ * Im Netz finden sich Infos ueber LFSRs und Tabellen fuer maximum-length
+ * feedback polynomials (M-Sequence Feedback Taps), falls jemand braucht.
+ *
+*/
+#pragma strong_types,rtt_checks,pedantic
+
+#include <tls.h>
+
+// Default-Polynom ist das:
+// x^32 + x^31 + x^28 + x^27 + x^24 + x^23 + x^20 + x^19 + x^16 + x^15 + x^12
+// + x^11 + x^8 + x^7 + x^5 + x^3 + 1
+// Taps: 32, 31, 28, 27, 24, 23, 20, 19, 16, 15, 12, 11, 8, 7, 5, 3
+// Binary: 110011001100110011001100110101000
+#define DEFAULTP 0x1999999a8
+// Andere gebraeuchliche:
+// x^32 + x^30 + x^26 + x^25 + 1,
+// Taps 32, 30, 26, 25
+// Binary: 101000110000000000000000000000000
+//#define DEFAULTP 0x146000000
+// x^16 + x^14 + x^13 + x^11 + 1
+// Taps 16, 14, 13, 11
+// Binary: 1011010000000000
+//#define DEFAULTP 0xB400
+
+private int polynom = DEFAULTP;
+private int state = 2553647223;
+//private int period;
+
+public varargs void init(int seed, int newp)
+{
+ if (!seed)
+ raise_error("Illegal seed 0\n");
+ // Es darf nur ein 32 bit breiter Seed verwendet werden. Die oberen 32 bit
+ // werden mit den unteren 32 bit XOR-rt (also, einmal die oberen 32 shiften
+ // und einmal die oberen 32 wegmaskieren.
+ seed = ((seed>>32) & 0xffffffff) ^ (seed & 0xffffffff);
+ //printf("Seed: %064b - 0x%x\n",seed,seed);
+
+ if (!seed)
+ raise_error("Illegal reduced seed: 0\n");
+
+ state = seed;
+ polynom = newp || DEFAULTP;
+}
+
+public void InitWithUUID(string uuid)
+{
+ string md5hash = hash(TLS_HASH_MD5, uuid);
+ int seed;
+ // 8 Bytes aus dem Hash ermitteln
+ foreach(int b: 16)
+ {
+ // Jeweils zwei Zeichen herausschneiden und als Hexadezimalzahl
+ // interpretieren, was jeweils ein byte (8 bit) gibt.
+ int tmp = to_int("0x"+md5hash[b*2..b*2+1]);
+ // diese werden dann in eine 64 bit breite Zahl zusammengefasst. Das
+ // gerade ermittelte Byte wird nach links geshiftet und mit dem, was da
+ // ggf. schon steht, XORred. Ist der int voll, faengt man wegen Modulo 64
+ // wieder rechts an.
+ //printf("S: %064b - %08b\n",seed,tmp);
+ seed = seed ^ (tmp << ((b*8)%64));
+ //printf("S: %064b - 0x%x\n",seed, seed);
+ }
+ //printf("Seed: 0x%x - %b\n",seed,seed);
+ init(seed);
+}
+
+public int nextbit()
+{
+ // Get LSB (i.e., the output bit).
+ int lsb = state & 1;
+ // Shift register by one bit
+ state >>= 1;
+ // Apply a toggle mask, which flips all the tap bits, _if_ the output bit is
+ // 1. The mask has 1 at bits corresponding to taps, 0 elsewhere. In other
+ // words, the polynom from above.
+ if (lsb)
+ state ^= polynom;
+ // debug check ;-)
+ if (!state)
+ raise_error("State must not be zero, but it is.\n");
+ //++period;
+ //printf("State: %032b (Period: %d)\n",state,period);
+ return lsb;
+}
+
+public int nextbits(int count)
+{
+ int result;
+ if (count>64)
+ raise_error(sprintf("Count is %d, but must be <= 64.\n",count));
+ foreach(int i: count)
+ result = (result << 1) | nextbit();
+ return result;
+}
+
+public int nextbyte()
+{
+ return nextbits(8);
+}
+
+public int random(int n)
+{
+ int rnd = nextbits(32);
+ //generates a random number on [0,1)-real-interval
+ float tmp = rnd * (1.0/4294967296.0);
+ // Skalieren auf [0,n)
+ return to_int(tmp * n);
+}
+
+// Just skip some bits and discard them.
+public void skipbits(int count)
+{
+ foreach(int i: count)
+ nextbit();
+}
+
+
+public void dumpstream(string file, int bytes)
+{
+ int *stream = allocate(bytes);
+ foreach(int i: bytes)
+ {
+ stream[i] = nextbits(8);
+ }
+ write_file(file, sprintf("%@c",stream));
+}
+
+public int Configure(int data)
+{
+ if (!data)
+ return state;
+
+ if (!intp(data))
+ return 0;
+ state = data;
+ return 1;
+}
+
diff --git a/std/util/ringbuffer.c b/std/util/ringbuffer.c
new file mode 100644
index 0000000..19338e1
--- /dev/null
+++ b/std/util/ringbuffer.c
@@ -0,0 +1,210 @@
+// MorgenGrauen MUDlib
+/** \file /std/util/ringbuffer.c
+* Implmentiert einen Ringbuffer in LPC.
+* Ab und an hat man den Fall, dass man Ereignisse/Meldungen o.ae. hat, von
+* denen man immer genau die letzten x gespeichert und abrufbar vorhalten
+* moechte. Dieses File stellt eine Datenstruktur und dazugehoerige
+* Verwaltungsfunktionen zu Verfuegung, mit denen dies effizient moeglich ist.
+* Insbesondere umgehen diese das staendige Slicing von Arrays, mit denen
+* haeufig Ringpuffer gebaut werden. Hierbei wird das Schreiben in den Puffer
+* billiger, das Abrufen der Daten allerdings teurer. Wird der Puffer haeufiger
+* abgefragt als beschrieben, ist dies keine effiziente Loesung.
+*
+* \author Zesstra
+* \date 22.05.2008
+* \version $Id$
+*/
+/* Changelog:
+*/
+#pragma strong_types
+#pragma save_types
+#pragma no_clone
+#pragma no_inherit
+#pragma no_shadow
+#pragma pedantic
+#pragma range_check
+
+#include <util/ringbuffer.h>
+
+/** Standardgroesse fuer Ringbuffer.
+ */
+#define MAXCOUNT 30
+
+
+/** Struktur, die einen Ringpuffer speichert.
+ Der Puffer selber ist im wesentlichen ein Array. Hinzu kommt noch ein
+ Zaehler, der den naechsten zu ueberschreibenden Wert indiziert sowie einen
+ Modus, der die Reihenfolge beim Abrufen beshreibt:
+ MODE_FIFO: First-in-First-out (default)
+ MODE_LIFO: Last-in-First-out
+ */
+struct std_ringbuffer {
+ mixed rbuffer;
+ int mode;
+ int next;
+};
+
+/** Erzeugt einen neuen Ringbuffer und liefert ihn zurueck.
+ Die Funktion erzeugt einen neuen, leeren Ringbuffer der Groesse \a size
+ und mit Ausgabemodus \a newmode und liefert die entsprechende
+ Ringbuffer-Struktur zurueck.
+ \attention Die zurueckgelieferte Datenstruktur bitte nicht per Hand
+ manipulieren.
+ \param[in] size Groesse des zu erzeugenden Ringbuffers. Default: 30
+ \param[in] newmode Ausgabemodus des Ringbuffers: \a MODE_FIFO oder
+ \a MODE_LIFO. Default: MODE_FIFO
+ \return Der erzeugte Ringbuffer (struct vom Typ std_ringbuffer).
+ \sa ResizeRingBuffer, RingBufferPut, RingBufferGet
+ */
+protected struct std_ringbuffer CreateRingBuffer(int size, int newmode) {
+
+ struct std_ringbuffer buffer = (<std_ringbuffer>
+ rbuffer: allocate(size||MAXCOUNT, 0),
+ mode: newmode || MODE_FIFO,
+ next: 0 );
+
+ // Bei LIFO von oben anfangen.
+ if (newmode==MODE_LIFO)
+ buffer->next = sizeof(buffer->rbuffer);
+
+ return buffer;
+}
+
+/** Schreibt einen neuen Wert in den Ringbuffer.
+ Diese Funktion schreibt einen neuen Wert in den Ringbuffer \a buffer und
+ loescht dabei ggf. den aeltesten Wert im Puffer.
+ \param[in,out] buffer zu aendernder Ringbuffer
+ \param[in] val hinzuzufuegender Wert
+ \sa CreateRingBuffer, ResizeRingBuffer, RingBufferGet
+ */
+protected void RingBufferPut(struct std_ringbuffer buffer, mixed val) {
+ int next = buffer->next;
+ // je nach Ausgabemodus von oben nach unten oder von unten nach oben die
+ // Werte reinschreiben.
+ switch(buffer->mode) {
+ case MODE_LIFO:
+ // next ist hier eigentlich ein 'last'. Dekrementieren und dann zum
+ // Indizieren benutzen.
+ buffer->rbuffer[--next] = val;
+ // wenn man gerade in Element 0 geschrieben hat, ist naechstes Element
+ // sizeof()-1, d.h. sizeof() als next vermerken.
+ next ||= sizeof(buffer->rbuffer);
+ break;
+ default:
+ // Wert schreiben und next inkrementieren.
+ buffer->rbuffer[next++] = val;
+ // wird sizeof() erreicht, ist das naechste Element 0. Etwas schneller
+ // waere ein Modulo mit der Buffergroesse direkt bei der Indizierung
+ // oben, aber dann kann es u.U. durch einen numerischen Overflow buggen.
+ if (next==sizeof(buffer->rbuffer))
+ next = 0;
+ }
+ buffer->next = next;
+}
+
+/** Liefert ein Array mit allen Werten des Ringbuffers \a buffer.
+ Das zurueckgelieferte Array enthaelt alle Daten des Ringbuffers in der
+ beim Erstellen des Puffers gewuenschten Reihenfolge (s. MODE_FIFO,
+ MODE_LIFO).
+ Ist der Puffer noch nicht vollstaendig gefuellt, enthalten die bisher noch
+ nie beschriebenen Elemente 0.
+ \param[in] buffer Ringpuffer, dessen Daten ausgeben werden sollen.
+ \return Array mit Daten des Puffers.
+ \sa CreateRingBuffer, RingBufferPut, ResizeRingBuffer
+ */
+protected mixed RingBufferGet(struct std_ringbuffer buffer) {
+ int size = sizeof(buffer->rbuffer);
+ int next = buffer->next;
+ mixed rbuffer = buffer->rbuffer;
+
+ switch(buffer->mode) {
+ case MODE_LIFO:
+ // der hintere Teil enthaelt die neueren Daten. Die kommen zuerst.
+ // Wenn next == sizeof(), dann kann das interne Array einfach kopiert
+ // werden.
+ if (next == size)
+ return copy(rbuffer);
+ else
+ return rbuffer[next .. size-1] + rbuffer[0 .. next-1];
+ default:
+ // der vordere Teil enthaelt die neueren Daten. Also zuerst den hinteren
+ // ausgeben, dann den vorderen.
+ // Wenn next 0, kann das interne Array einfach kopiert werden. Sonst
+ // muss es zusammengesetzt werden.
+ if (next)
+ return rbuffer[next .. size-1] + rbuffer[0 .. next-1];
+ else
+ return copy(rbuffer);
+ }
+ return 0;
+}
+
+/** Erzeugt einen neuen Ringbuffer der Groesse \a size und dem gleichen Modus
+ * wie \a buf, der dieselben Daten enthaelt wie \a buf.
+ * Diese Funktion erzeugt einen neuen Ringbuffer und kopiert alle Daten aus
+ * dem alten Puffer in den neuen um.
+ \param[in] buf alter Ringbuffer
+ \param[in] size gewuenschte neue Groesse
+ \return Liefert neuen Ringbuffer mit gewuenschten Groesse.
+ \sa CreateRingBuffer, RingBufferPut, RingBufferGet
+ \attention Wird der Ringbuffer verkleinert, kommt es zum Verlust der
+ aeltesten Daten, die nicht mehr in den neuen hineinpassen.
+ \todo Effizientere Implementation.
+ */
+protected struct std_ringbuffer ResizeRingBuffer(struct std_ringbuffer buf,
+ int size) {
+ // neuen Ringbuffer anlegen.
+ struct std_ringbuffer nbuf = CreateRingBuffer(size, buf->mode);
+ // und alle daten aus dem alten wieder reinstopfen.
+ // ja, das geht effizienter, hab ich gerade aber keinen Bock drauf. Die
+ // Funktion wird vermutlich eh sehr selten gerufen.
+ foreach(mixed val: RingBufferGet(buf))
+ RingBufferPut(nbuf, val);
+ // neuen Buffer zurueckgeben. Der alte bleibt unveraendert!
+ return nbuf;
+}
+
+/* halbfertige Implementation mit Arrays.
+#define RBUFFER 0
+#define MODE 1
+#define COUNTER 2
+
+protected mixed CreateRingBuffer(int size, int mode) {
+ mixed buffer = ({ allocate(size||MAXCOUNT, 0),
+ mode || MODE_FIFO,
+ 0 });
+ if (mode==MODE_LIFO)
+ buffer[COUNTER] = sizeof(buffer[RBUFFER]);
+ return buffer;
+}
+
+protected void RingBufferPut(mixed buffer, mixed val) {
+ int counter = buffer[COUNTER];
+ switch(mode) {
+ case MODE_LIFO:
+ rbuffer[--counter] = val;
+ counter ||= sizeof(rbuffer);
+ break;
+ default:
+ rbuffer[(counter++)%sizeof(rbuffer)] = val;
+ }
+ buffer[COUNTER]=counter;
+}
+
+protected mixed RingBufferGet(mixed buffer) {
+ int size=sizeof(rbuffer);
+
+ switch(mode) {
+ case MODE_LIFO:
+ return rbuffer[counter..size] + rbuffer[0..counter-1];
+ default:
+ if (counter%size)
+ return rbuffer[(counter%size) .. size-1]
+ + rbuffer[0..(counter%size)-1];
+ else
+ return copy(rbuffer);
+ }
+}
+
+protected mixed test() {return rbuffer;}
+*/
diff --git a/std/util/testedit.c b/std/util/testedit.c
new file mode 100644
index 0000000..f31f6ed
--- /dev/null
+++ b/std/util/testedit.c
@@ -0,0 +1,25 @@
+// MorgenGrauen MUDlib
+//
+// util/testedit.c -- Tragbarer Editor
+//
+// $Id: testedit.c 6371 2007-07-17 22:46:50Z Zesstra $
+#pragma strict_types
+#pragma save_types
+#pragma pedantic
+#pragma range_check
+#pragma no_clone
+
+inherit "/std/thing";
+inherit "/std/util/ex";
+
+#include <properties.h>
+
+void create()
+{
+ ::create();
+ AddId("ex");
+ SetProp(P_NAME, "Editor");
+ SetProp(P_SHORT, "Ein Testeditor");
+ SetProp(P_LONG, "Testeditor: Kommando: ex\n");
+ AddCmd("ex", "ex");
+}