ldmud-3.2.9/doc/
ldmud-3.2.9/doc/efun/
ldmud-3.2.9/mud/
ldmud-3.2.9/mud/heaven7/
ldmud-3.2.9/mud/heaven7/lib/
ldmud-3.2.9/mud/lp-245/
ldmud-3.2.9/mud/lp-245/banish/
ldmud-3.2.9/mud/lp-245/doc/
ldmud-3.2.9/mud/lp-245/doc/examples/
ldmud-3.2.9/mud/lp-245/doc/sefun/
ldmud-3.2.9/mud/lp-245/log/
ldmud-3.2.9/mud/lp-245/obj/Go/
ldmud-3.2.9/mud/lp-245/players/lars/
ldmud-3.2.9/mud/lp-245/room/death/
ldmud-3.2.9/mud/lp-245/room/maze1/
ldmud-3.2.9/mud/lp-245/room/sub/
ldmud-3.2.9/mud/lp-245/secure/
ldmud-3.2.9/mud/morgengrauen/
ldmud-3.2.9/mud/morgengrauen/lib/
ldmud-3.2.9/mud/sticklib/
ldmud-3.2.9/mud/sticklib/src/
ldmud-3.2.9/mudlib/uni-crasher/
ldmud-3.2.9/pkg/
ldmud-3.2.9/pkg/debugger/
ldmud-3.2.9/pkg/diff/
ldmud-3.2.9/pkg/misc/
ldmud-3.2.9/src/autoconf/
ldmud-3.2.9/src/bugs/
ldmud-3.2.9/src/bugs/MudCompress/
ldmud-3.2.9/src/bugs/b-020916-files/
ldmud-3.2.9/src/bugs/doomdark/
ldmud-3.2.9/src/bugs/ferrycode/ferry/
ldmud-3.2.9/src/bugs/ferrycode/obj/
ldmud-3.2.9/src/bugs/psql/
ldmud-3.2.9/src/done/
ldmud-3.2.9/src/done/order_alist/
ldmud-3.2.9/src/done/order_alist/obj/
ldmud-3.2.9/src/done/order_alist/room/
ldmud-3.2.9/src/gcc/
ldmud-3.2.9/src/gcc/2.7.0/
ldmud-3.2.9/src/gcc/2.7.1/
ldmud-3.2.9/src/hosts/
ldmud-3.2.9/src/hosts/GnuWin32/
ldmud-3.2.9/src/hosts/amiga/NetIncl/
ldmud-3.2.9/src/hosts/amiga/NetIncl/netinet/
ldmud-3.2.9/src/hosts/amiga/NetIncl/sys/
ldmud-3.2.9/src/hosts/i386/
ldmud-3.2.9/src/hosts/msdos/byacc/
ldmud-3.2.9/src/hosts/msdos/doc/
ldmud-3.2.9/src/hosts/os2/
ldmud-3.2.9/src/hosts/win32/
ldmud-3.2.9/src/util/
ldmud-3.2.9/src/util/erq/
ldmud-3.2.9/src/util/indent/hosts/next/
ldmud-3.2.9/src/util/xerq/
ldmud-3.2.9/src/util/xerq/lpc/
ldmud-3.2.9/src/util/xerq/lpc/www/
Short: Improved RegExps, using PCRE
From: Lars, Fini
Date: 20010406
State: New

Ach, dann ging mein pcre-Patch nicht mehr. Ich habs also von Hand machen
muessen und dabei ist mir aufgefallen, dass ich sogar in der
Non-Pcre-Sektion etwas geaendert habe. Und zwar in array.c bei Zeile 2871:

        if (!match)
        {
+ #ifndef USE_PCRE
+             REGFREE(reg);
+ #else
+             pcregex_free(reg);
+ #endif
            error("Stack overflow in regexplode()");
            /* NOTREACHED */
            return NULL;
        }

Das ist vielleicht eigentlich nicht noetig, aber irgendwas war da doch mit
einem Refcount und so, das kommt dann wohl durcheinander. Kann mich nur
dunkel an irgendson Refcount erinnern, ich glaub den brauchte man wegen
rekursiven REs die kollidieren oder so *denk*

------------

> Mhm, ich kenne die Perl REs zwar nicht so gut (willst du nur die 
> Funktionalitaet in efuns verpackt, oder auch Sprachaenderungen); aber gerade 
> gestern habe ich die PCRE ("Perl Compatible Regular Expressions") Library 
> gefunden, was eine zukuenftige Implementierung erheblich vereinfacht.

Aehm, ich wollte nur dass man bei den vorhandenen efuns auch
'vernuenftige' RE benutzen kann. Was mir zb extrem fehlt ist ein 'non
greedy *' Operator, also der beliebig viele, jedoch so wenig wie moeglich
Wiederholungen der vor RE nimmt. In Perl macht man das mit einem
angehaengten '?'. Mal sehen ob ich ein Beispiel finde...

      $skill = $1   if ( /"skills":(.*?]\))/ );

Das Perlskript liest ein LPC .o-File ein. Dort gibt es ein Mapping
(properties), welches mit dem Schluessel 'skills' ein Mapping hat, was die
Skills repraesentiert. Ich will also beliebige Zeichen haben bis zum
ersten Auftreten von ']'. In diesem Fall koennte man auch schreiben
[^\]]* aber es gibt andere Faelle (zb kann man mit REs sehr schoen Strings
aus Savefiles rausholen, unter Beachtung von gequoteten " usw, da geht das
nicht oder nur mit erheblichem Aufwand. (Ganz unten haenge ich dir maln
Beispiel ran, was die \" beachtet und so weiter und '?' nutzt)

Also wenn die reg*(E) das (auch) nehmen wuerden waer das schon ganz schoen
klasse. Wenn man da das PCRE einbinden koennte (muesste man bestimmt
wieder einen neuen Schalter einbauen, welche Art von Regexps man denn will
grumpf)...

Aenderungen an efuns, da faellt mir ein, ein regexplode welches nicht die
delimiter mitliefert waer auch bequem (analog Perls split, dort kann man
beides haben wie man will). Schoen waer in dem Zusammenhang auch ein
'Suche in dem String str nach Regexp RE und liefer mir das'. ZZ ist das
sehr aufwenidig in einem String was zu suchen und das dann zu benutzen.
Natuerlich kann ich strs = regexplode(str, RE); machen und dann die
Groesse von strs pruefen und mein Zielstring ist dann strs[1]. ;o)
Aber ziel = xxx(str, RE); (Irgendwie scheint mir das zu keiner vorhandenen
Efun zu passen).


Knuddels und Gruss aus dem verregneten Hamburg

  Fini


----
Wieder eine Property. Im Mapping ist hinter dem Schluessel 'explored' ein
LPC-Bitstring. Wenn man den komplett haben will muss man wissen wo er
zuende ist, also schoen alle " zaehlen und dabei \" ignorieren.

      $explo = $1   if ( /"explored":"(.*?[^\\]+?(\\\\)*?)"/ );

Ich glaub irgendwann muss ich maln Perl Package schreiben was einfach
jedes .o File einlesen kann und ein entsprechendes Mapping (hash)
zurueckliefert in dem alle Vars dann abgebildet werden *grueble* ich
schick dir das dann ;o) Mal sehen ob beim Driver die Docu zu den Savefiles
schon gut genug ist ;o))

----
Zum Regex Kram fiel mir noch ein, dass es schoen waere, wenn man regexp()
auch ohne Array benutzen kann, wenn man nur sehen will ob ein String passt
muss man den zZ via sizeof(regexp(({str}), re)) testen. Je mehr ich
darueber nachdenke, desdo weniger trivial erscheint es mit mit den
PerlREs. Die koennen in Perl naemlich verschiedene Modi haben, die man nun
eigentlich mituebergeben koennen muesste. Ausserdem sollte man auch auf
die Klammerausdruecke zugreifen koennen, dort waere am besten irgendwie
sowas...

  n_regexp(string str, string RE, string parameter).

Wenn 'parameter' nicht gegeben ist, wird der normale endliche Automat des
Muds benutzt. Sonst wird halt der Perl-Automat benutzt, der die Parameter
erhaelt. Wenn die RE gefunden wird lieferts 'wahr' sonst 'unwahr'.
Weiterhin (und deswegen wuerde ich die Efuns trennen dh anders nennen)
waere eine Unterstuertzung fuer die Rueckwaertsreferenzen klasse. Also
was man bei regreplace mit \1 usw erhalten kann. Ich traeume mir vor, dass
ich an n_regexp() nun auch angeben kann, welche Referenzen mich
interessieren und die liefert es dann als Array. (Da das doch sehr anders
ist als regexp() eine andere Efun.)
Also parameter = "ig\1\5\9" oder so ('\'s sollen "\\" sein ;o).


Btw kann man den (nichtdeterministischen) Automaten mit einer Zeile in die
ewigen Jagdgruende schicken ('regular expressions' von oreilly entnommen):

 regexp(({"=XX============================================"}), "X(.+)+X")

Eventuell sollte man in dem FA halt einfach jedem Backtracking eine
eval-cost zuordnen um das zu verhindern (die Laufzeit des Matchens oben
ist propotional pow(2, strlen)). Das waere zB moeglich bei Zeile 1158 des
regexp.c:
                        return MY_TRUE;
                /* Couldn't or didn't -- back up. */
                no--;
+               evals += 5;
+               if (evals > evals_max) regerror("too many backtracks");
                reginput = save + no;
            }

(mit evals und evals_max symbolisch fuer die Kosten). Ich schlage gerade
vor genau DAS als Kriterium zu nehmen, weil das ziemlich sicher soetwas
unendliches erkennt, alles andere kann auch 'viel' werden, aber da kanns
trotzdem gleich fertig sein.
----------

Hmm, hatte heute ein wenig Zeit und hab mir mal das PCRE Paket
angeschaut. Das ist ja wirklich supereinfach zu benutzen. Konnte dann dem
nicht wiederstehen, es gleich mal in den Driver reinzufummeln. Das
Resultat hab ich dir mal als diff angehaengt.

Es funktioniert alles genau so wie ich es mir ertraeume ;o) naja, fast.
Auf jeden Fall so aehnlich wie ichs in den Mails an dich beschrieb.
Was bei dem Diff absolut fehlt ist eine 'richtige' Integration. Sprich man
muss das Paket sich selbst holen und die Bibliothek erzeugen. Ausserdem
sind noch feste Pfade drin, halt die meiner Testumgebung. Weitere
Aenderungen die ich am Makefile vorgenommen hab unten.

Ich hab keine Ahnung ob dir der Code gefaellt, und ich muss auch sagen ich
hab noch nie was am Driver gemacht, keine Ahnung zB ob ich irgendwo ein
Speicherloch eingenaut hab (wegen Strings zB). Da das alles ueber xalloc()
laeuft bin ich aber guter Hoffnung.

Wenn du meinst, dass ich auf dem richtigen Wege bin, kann ich da gerne
weitermachen; das 3. Argument haette ich gerne optional, die Manpage fehlt
auch noch, es kostet keine evals, die compilierten Regexs werden nicht
gebuffert und so weiter und so fort.

Ich hoffe das bringt den Driver einen Schritt naeher an 'richtige' Regexs.


Gruesse aus dem inzwischen dunklen Hamburg,

   Fini


----

Zum PCRE-Paket: Also erstmal haben die sonne komische Licence, die
teilweise die GPL ueberdecken koennte (ich glaube der Driver ist unter
GPL, oder? *gg*). Da muesste dann mal wer schauen, ob man das Paket mit in
die Dist packen darf oder nicht. Letztere waere natuerlich aeusserst
laestig.

Gut. Dann zum Testen hab ich das ganze statisch gelinkt gehabt, weil ich
compiliere und teste auf verschiedenen Systemen. Das funzte auch soweit
ganz gut. Da ich keinerlei Rechte auf dem Compilier-Rechner hab, hatte ich
den Pcre-Krempel in einem Nachbarverzeichnis liegen. In dem Makefile hab
ich dann das Dazulinken aktiviert durch
LIBS=-lm  -lcrypt -lpcre -L/mud/src/pcre-3.4/ -static
wenn das 'richtig' in die Driver-Dist kommt muesste das natuerlich alles
automagisch gehen ;o)

Btw den Automaten kann man (selbstverstaendlich) mit derselben Regex von
letztens in eine 'unendliche' Schleife schicken. Wie man dort dann
nachtraeglich Evalkosten pro Backtrack einbaut *gruebel*...
Uebrigens ist der Pcre-Automat etwa doppelt so schnell bei der Schleife,
20 '=' nach den XX dauern bei mir 2 bzw 4 Sekunden.
---------------------------------------------------------------------------
Hallo Mateese!

Hmm, hatte heute ein wenig Zeit und hab mir mal das PCRE Paket
angeschaut. Das ist ja wirklich supereinfach zu benutzen. Konnte dann dem
nicht wiederstehen, es gleich mal in den Driver reinzufummeln. Das
Resultat hab ich dir mal als diff angehaengt.

Es funktioniert alles genau so wie ich es mir ertraeume ;o) naja, fast.
Auf jeden Fall so aehnlich wie ichs in den Mails an dich beschrieb.
Was bei dem Diff absolut fehlt ist eine 'richtige' Integration. Sprich man
muss das Paket sich selbst holen und die Bibliothek erzeugen. Ausserdem
sind noch feste Pfade drin, halt die meiner Testumgebung. Weitere
Aenderungen die ich am Makefile vorgenommen hab unten.

Ich hab keine Ahnung ob dir der Code gefaellt, und ich muss auch sagen ich
hab noch nie was am Driver gemacht, keine Ahnung zB ob ich irgendwo ein
Speicherloch eingenaut hab (wegen Strings zB). Da das alles ueber xalloc()
laeuft bin ich aber guter Hoffnung.

Wenn du meinst, dass ich auf dem richtigen Wege bin, kann ich da gerne
weitermachen; das 3. Argument haette ich gerne optional, die Manpage fehlt
auch noch, es kostet keine evals, die compilierten Regexs werden nicht
gebuffert und so weiter und so fort.

Ich hoffe das bringt den Driver einen Schritt naeher an 'richtige' Regexs.


Gruesse aus dem inzwischen dunklen Hamburg,

   Fini


----

Zum PCRE-Paket: Also erstmal haben die sonne komische Licence, die
teilweise die GPL ueberdecken koennte (ich glaube der Driver ist unter
GPL, oder? *gg*). Da muesste dann mal wer schauen, ob man das Paket mit in
die Dist packen darf oder nicht. Letztere waere natuerlich aeusserst
laestig.

Gut. Dann zum Testen hab ich das ganze statisch gelinkt gehabt, weil ich
compiliere und teste auf verschiedenen Systemen. Das funzte auch soweit
ganz gut. Da ich keinerlei Rechte auf dem Compilier-Rechner hab, hatte ich
den Pcre-Krempel in einem Nachbarverzeichnis liegen. In dem Makefile hab
ich dann das Dazulinken aktiviert durch
LIBS=-lm  -lcrypt -lpcre -L/mud/src/pcre-3.4/ -static
wenn das 'richtig' in die Driver-Dist kommt muesste das natuerlich alles
automagisch gehen ;o)

Btw den Automaten kann man (selbstverstaendlich) mit derselben Regex von
letztens in eine 'unendliche' Schleife schicken. Wie man dort dann
nachtraeglich Evalkosten pro Backtrack einbaut *gruebel*...
Uebrigens ist der Pcre-Automat etwa doppelt so schnell bei der Schleife,
20 '=' nach den XX dauern bei mir 2 bzw 4 Sekunden.

---------------------------------------------------------------------------
Hallo Mateese!

Hab grad nochmal ein bissl Zeit gefunden und hab mal geschaut ob ich
den rxcache nicht irgendwie mitbenutzen kann. So schwierig scheint das
nicht zu sein, ich muesste nur den Wert von from_ed irgendwie
erweitern, dass man pcre-Ausdruecke erkennen kann.

Am eigentlichen Code habe ich nicht viel getan, ausser ihn nach array.c
zu verschieben, was mE aber auch kein besonders schoener Platz ist.
Immerhin sind dort mehr verwandet Funktionen als im backend.c.
Irgendwie funzt nun auch dynamisches linken.

Dann sollte man natuerlich auch in den anderen reg* Funktionen die
perlaehnlichen Ausdruecke verwenden koennen. 'normale' sollten einfach
so zu ersetzen sein, die excompat muesste man ein bissl vorher
anpassen - wenn man einfach fuer alles pcre nehmen will. Ich denke das
ist der einfachste Ansatz anstatt zwei Automaten parallel zu nutzen.
Was sagst du dazu.

Hmm, ich sehe gerade einen Fehler im rxcache *g*:
regreplace("1(ab)", "1\\(ab\\)*", "AAA", 0)  ->  "AAA"
regreplace("1(ab)", "1\\(ab\\)*", "AAA", 2)  ->  "AAA"

Das 2. Ergebnis ist falsch, es wird einfach die nicht-ex-Regex aus
dem Cache genommen. Das richtige Ergebnis waere:
regreplace("2(ab)", "2\\(ab\\)*", "AAA", 2)  ->  "AAA(ab)"

Hmm, stimmt, regcomp_cache() prueft nur ob from_ed uebereinstimmt, auf
excompat wird gar keine Ruecksicht genommen, in regexp ist ja auch
gar kein Datenfeld dafuer vorgesehen. Man koennte dort from_ed als
allgemeines Flag nehmen, oder *grins* steigen wir gleich um auf
pcre? Naja, ist wohl noch nie jemandem aufgefallen, ich wuesste aber
auch nicht wer den bloeden ex-Modus ueberhaupt nutzen wollen sollte ;)

Ach, eine Hilfeseite hab ich mal angefangen, damit du weisst was
ueberhaupt die Efun macht.

Ich wuerde also gerne wissen, in welcher Richtung es weitergehen soll. Wie
ich es am liebsten haette weisst du ja, ich wuerde den rxcache umschreiben
und die alten regexs rauswerfen, und diese pcregexp(E) irgendwie sinnvoll
umbennenen oder evt mit in regexp(E) legen (wenn Arg 1 kein Array ist),
aber das ist dann alles wieder so unuebersichtlich fuer Magier. Weiterhin
hab ich keine Ahnung was der Unterscheid von TEFUN usw ist (nur sehr
grob), was fuer ein Typus es werden soll muesstest du sagen. Das Einbinden
vom Pcre-Paket weiss ich auch nicht wie das geht. Also von Hand schon,
aber wie soll es beim Driver sein? Auch 'extern' builden und dynamisch
linken oder besser den Code mitreinziehen? Aber was ist mit dem configure
des Paketes, da muss ja auch abhaengiger Code sein usw usf... Seufz.


Nagut. Das wars erstmal aus Hamburg,

   Fini

---------------------------------------------------------------------------
Hallo Mateese!

Was auch schoen waere zu haben, waere wenn der 3. Parameter von
regreplace() auch eine Closure sein koennte. Dort steht jetzt
der Ersatzstring. Wenn es eine Closure ist, so sollte diese den
Originaltext bekommen und den Ersatztext zurueckliefern.

Das ist besonders dann nuetzlich, wenn man mit etwas 'nichtstatischem'
ersetzen will. Zz muss man dazu mit regexplode() den String zerteilen
und dann mit 2er Schritten durchgehen und ersetzen.

Beispiel:
Eine Funktion mixed_to_string(), die alles in ein lesbares Format
wandelt (ist eine simul_efun bei uns, ist mE lesbarer als %O).
Nun moechte ich alle Zeichen des Strings, die kleiner als ' ' sind
durch ihre Kuerzel ersetzen. Bei \n \t usw kein Problem. Doch was
ist mit beliebigen anderen Sequenzen? (%O liefert dort einfach NIX,
nicht sehr nuetzlich).

regreplace(str, "[^ -~]", (: sprintf("\\%03d", $1[0]) :), 1);

wuerde das sehr 'elegant' loesen. Zur Zeit ist unser Konstrukt dort
eher unuebersichtlich:

mix = regexplode(mix, "[^ -~]");
for (i = sizeof(mix)-2; i>0; i-=2) 
  mix[i] = sprintf("\\%03d", mix[i][0]);
mix = implode(mix, "");

----

Fuer die bislang pcregexp() genannte Funktion wuerde ich uebrigens
regmatch() vorschlagen als Namen, das passt besser in die vorhandenen
reg*() Namen rein - und nach meinen Vorstellungen sollen ja (optional)
alle reg* mit pcre laufen, so ist die Unterscheidung im Funnamen
ueberfluessig.


Cheers,

  Fini

----------------------------------------------------------------------
Date: Thu, 26 Jul 2001 23:41:51 +0200 (MEST)
From: Erzmagier des Wunderlandes <mud@hurrikap.rz.uni-leipzig.de>
To: Lars Duening <lars@bearnip.com>
Subject: Ldmud: pcre
Message-ID: <Pine.LNX.4.10.10107262307100.22388-200000@hurrikap.rz.uni-leipzig.de>

  This message is in MIME format.  The first part should be readable text,
  while the remaining parts are likely unreadable without MIME-aware tools.
  Send mail to mime@docserver.cac.washington.edu for more info.

--311121419-828061240-996183711=:22388
Content-Type: text/plain; charset=us-ascii

Hallo Mateese!

So, da wir morgen in See stechen und ueber die Nordsee segeln gips heute
schon ein diff. Zum groessten Teil ist das fertig so umgesetzt wie in der
Mail besprochen. Das Diff ist eigentlich fuer 313, aber es geht auch auf
314 hab ich grad getestet. Den Code selbst habe ich nicht superdoll
getestet, das kommt dann naechste Woche dran. Ich kann nur nicht
wiederstehen dir schonmal zu schicken was ich hab ;o)

* Der rx-Cache kann nun auch mit PCREs umgehen

  Beide Arten (bzw drei sind es ja jetzt) werden parallel im gleichen
  Hash gehalten. Um die pcres musste dazu eine Struktur gewickelt werden
  fuers Refcounting. Leider kann man das dann nicht mehr 'in einem
  Stueck' free()n, also gibt es unterschiedliche Funs je Art. Ich hatte
  verschiedene Datenstrukturen probiert, was besseres ist mir nicht
  eingefallen ohne alles umzustricken.

  Im rx-cache war ein kleiner Quirk, der Speicherzaehler fuer 'status'
  wurde auch dann schon erniedrigt, wenn der Refcount einer RE noch nicht
  Null war, das habe ich etwas 'linearisiert'.

  Weiterhin Wrapper dort eingebaut, dass PCRE auch ohne Cache laufen
  kann, die anderen Module benutzen nie die echten pcre-Funktionen.

  Jede RE wird auch ge-study()-t. Das braucht mehr Speicher und Zeit,
  dafuer geht das Matchen schneller. Ob das lohnt? Typische REs aus dem
  Wunderland haben 60 Byte 'Body' und 0 bis 40, meist 15 Byte 'Study'.

  count_rxcache_refs() benutzt nicht mehr count_rxcache_ref(), da man
  dann die Typen nicht mehr unterscheiden koennte. Sind eh nur zwei
  Zeilen gewesen. Die letztere Funktion benutzt nur noch ed der nur
  alte REs benutzt.

  Den Strukt der Cache-Elemente hab ich auch mal ins .h gelegt.

* Main initialisiert die Benutzung der PCRE

* Array erhaelt erhaelt Erweiterungen
  und zwar die regmatch(E) die nur da ist wenn PCRE 'da' ist.
  Die Efuns regexp() und regexplode() benutzen auch PCRE.

* Lexer hat predefined macro __PCRE__

* (nicht im Diff) in config.h muss einfach USE_PCRE definiert werden
  um den ganzen Krempel anzuschalten.

* (nicht im Diff) Es muessen folgende Dateien von pcre dazugelinkt
  werden. Ich make-e nochmal das pcre-Paket ohne Install und linke
  pcre.o       -  Hauptroutinen
  study.o      -  Optimiert die REs
  get.o        -  Hilft Submatches extrahieren (kleine Hilfsfuns)
  maketables.o -  Erstellt die Char-Tables wie besprochen, kann man
                  weglassen wenn keine Locale-Aenderung zur Laufzeit
  Des weiteren muss in rxcache.h evt der Pfad zu pcre.h angepasst
  werden, der bei mir in ./pcre-3.4 liegt.

* Was noch fehlt:
  Eval-Costs und die regreplace() Funktion. Die ist jedoch dermassen
  naja, die wuerde ich zumindest fuer pcre komplett neu schreiben wollen.
  inter_sp evt an einigen Stellen setzen.



So. Vielleicht magst du ja mal reinschauen. Auf jeden Fall ein
schoenes (sonniges) Wochenende.


  Fini

--311121419-828061240-996183711=:22388
diff -c /mud/src/driver/3-2-dev/src/array.c ./array.c
*** /mud/src/driver/3-2-dev/src/array.c	Thu Jul 26 22:47:45 2001
--- ./array.c	Thu Jul 26 22:54:44 2001
***************
*** 2614,2620 ****
--- 2614,2626 ----
   */
  
  {
+ #ifndef USE_PCRE
      struct regexp *reg;        /* compiled regexp */
+ #else
+     pcregex* reg;              /* compiled perl regex */
+     int found;
+     int ergs[OVEC_LEN];
+ #endif
      CBool *res;                /* res[i] true -> v[i] matches */
      mp_int num_match, v_size;  /* Number of matches, size of <v> */
      vector_t *ret;             /* The result vector */
***************
*** 2625,2633 ****
--- 2631,2643 ----
          return allocate_array(0);
  
      /* Compile the regexp (or take it from the cache) */
+ #ifndef USE_PCRE
      reg = REGCOMP((unsigned char *)pattern, 0, MY_FALSE);
      if (reg == NULL)
          return NULL;
+ #else
+     reg = pcregex_cache(pattern, 0);
+ #endif
  
      /* Check every string in <v> if it matches and set res[]
       * accordingly.
***************
*** 2635,2641 ****
--- 2645,2655 ----
      res = alloca(v_size * sizeof(*res));
      if (!res)
      {
+ #ifndef USE_PCRE
          REGFREE(reg);
+ #else
+         pcregex_free(reg);
+ #endif
          error("Stack overflow in regexp()");
          /* NOTREACHED */
          return NULL;
***************
*** 2651,2658 ****
--- 2665,2685 ----
  
          eval_cost++;
          line = v->item[i].u.string;
+ #ifndef USE_PCRE
          if (regexec(reg, line, line) == 0)
              continue;
+ #else
+         found = pcre_exec(reg->pProg, reg->pHints, line, strlen(line),
+             0, 0, ergs, OVEC_LEN);
+ 
+         if (found == PCRE_ERROR_NOMATCH) continue;
+         if (found <= 0) {
+             pcregex_free(reg);
+             error("regexp: %s\n", pcre_error_message(found));
+             /* NOTREACHED */
+             return NULL;
+         }
+ #endif
  
          res[i] = MY_TRUE;
          num_match++;
***************
*** 2667,2673 ****
--- 2694,2704 ----
          num_match++;
      }
  
+ #ifndef USE_PCRE
      REGFREE(reg);
+ #else
+     pcregex_free(reg);
+ #endif
  
      return ret;
  }
***************
*** 2823,2829 ****
--- 2854,2867 ----
  
      char *text;                        /* Input text from the vm stack */
      char *pattern;                     /* Delimiter pattern from the vm stack */
+ #ifndef USE_PCRE
      struct regexp *reg;                /* Compiled pattern */
+ #else
+     pcregex* reg;
+     int found;
+     int ergs[OVEC_LEN];
+     size_t textlen;
+ #endif
      struct regexplode_match *matches;  /* List of matches */
      struct regexplode_match **matchp;  /* Pointer to previous_match.next */
      struct regexplode_match *match;    /* Current match structure */
***************
*** 2841,2853 ****
      text = sp[-1].u.string;
      pattern = sp->u.string;
  
      reg = REGCOMP((unsigned char *)pattern, 0, MY_FALSE);
!     if (reg == 0) {
          inter_sp = sp;
          error("Unrecognized search pattern");
          /* NOTREACHED */
          return NULL;
      }
  
      /* Loop over <text>, repeatedly matching it against the pattern,
       * until all matches have been found and recorded.
--- 2879,2895 ----
      text = sp[-1].u.string;
      pattern = sp->u.string;
  
+ #ifndef USE_PCRE
      reg = REGCOMP((unsigned char *)pattern, 0, MY_FALSE);
!     if (reg == NULL) {
          inter_sp = sp;
          error("Unrecognized search pattern");
          /* NOTREACHED */
          return NULL;
      }
+ #else
+     reg = pcregex_cache(pattern, 0);
+ #endif
  
      /* Loop over <text>, repeatedly matching it against the pattern,
       * until all matches have been found and recorded.
***************
*** 2855,2871 ****
--- 2897,2937 ----
      str = text;        /* Remaining <text> to analyse */
      num_match = 0;
      matchp = &matches;
+ #ifndef USE_PCRE
      while (regexec(reg, str, text)) {
+ #else
+     textlen = strlen(text);
+     while (PCRE_ERROR_NOMATCH !=
+         (found=pcre_exec(reg->pProg, reg->pHints, text, textlen,
+          str-text, 0, ergs, OVEC_LEN)))
+     {
+         if (found <= 0) {
+             pcregex_free(reg);
+             error("regexplode: %s\n", pcre_error_message(found));
+             /* NOTREACHED */
+             return NULL;
+         }
+ #endif
          eval_cost++;
          match = (struct regexplode_match *)alloca(sizeof *match);
          if (!match)
          {
+ #ifndef USE_PCRE
+             REGFREE(reg);
+ #else
+             pcregex_free(reg);
+ #endif
              error("Stack overflow in regexplode()");
              /* NOTREACHED */
              return NULL;
          }
+ #ifndef USE_PCRE
          match->start = reg->startp[0];
          match->end = str = reg->endp[0];
+ #else
+         match->start = text+ergs[0];
+         match->end = str = text+ergs[1];
+ #endif
          *matchp = match;
          matchp = &match->next;
          num_match++;
***************
*** 2876,2882 ****
--- 2942,2952 ----
  
      /* Prepare the result vector */
      if (max_array_size && num_match > ((max_array_size-1) >> 1) ) {
+ #ifndef USE_PCRE
          REGFREE(reg);
+ #else
+         pcregex_free(reg);
+ #endif
          inter_sp = sp;
          error("Illegal array size");
          /* NOTREACHED */
***************
*** 2915,2921 ****
--- 2985,2995 ----
      put_malloced_string(svp, string_copy(text));
  
      /* Cleanup */
+ #ifndef USE_PCRE
      REGFREE(reg);
+ #else
+     pcregex_free(reg);
+ #endif
      free_string_svalue(sp);
      sp--;
      free_string_svalue(sp);
***************
*** 2924,2929 ****
--- 2998,3124 ----
      put_array(sp, ret);
      return sp;
  }
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+ #ifdef USE_PCRE
+ svalue_t *
+ f_regmatch (svalue_t *sp)
+ 
+ /* TEFUN regmatch()
+  *
+  *   mixed* regmatch (string text, string pattern, int opt)
+  *
+  * Match the perl compatible regex pattern on string text and return an
+  * array or 0 if no match could be found.
+  *
+  * The array contains the matching part of string text as first element
+  * and the parts matching subpatterns in the following elements.
+  * If a subpattern was unused a zero will be in its place in contrast to
+  * an empty string which could occur on used subpatterns also.
+  * E.g.: arr[5] is alike \5.
+  *
+  * TODO: eval costs?!
+  */
+ 
+ {
+ 
+     char* text;
+     char* pattern;
+     int opt;
+ 
+     pcregex* regex;
+     int ergs[OVEC_LEN];
+     int found;
+ 
+     vector_t* matches;
+     svalue_t* svp;
+     int i, len;
+     const char* match;
+ 
+     /* Get the efun arguments */
+     if (sp[-2].type != T_STRING) bad_xefun_arg(1, sp);
+     if (sp[-1].type != T_STRING) bad_xefun_arg(2, sp);
+     if (sp[ 0].type != T_NUMBER) bad_xefun_arg(3, sp);
+ 
+     text    = sp[-2].u.string;
+     pattern = sp[-1].u.string;
+     opt     = sp[ 0].u.number;
+ 
+     /* compile the regex */
+     regex = pcregex_cache(pattern, opt);
+ 
+     /* use the regex */
+     /* TODO: support for pcre-options? */
+     found = pcre_exec(regex->pProg, regex->pHints, text, strlen(text),
+                                   0, 0, ergs, OVEC_LEN);
+ 
+     /* no match */
+     if (found == PCRE_ERROR_NOMATCH) {
+         pcregex_free(regex);
+         free_svalue(sp--);
+         free_string_svalue(sp--);
+         free_string_svalue(sp);
+         put_number(sp, 0);
+         return sp;
+     }
+ 
+     /* error occured */
+     if (found <= 0) {
+         inter_sp = sp;
+         pcregex_free(regex);
+         error("regmatch: %s\n", pcre_error_message(found));
+         /* NOTREACHED */
+         return NULL;
+     }
+ 
+     /* create result array */
+     if (max_array_size && found > (max_array_size-1)) {
+         pcregex_free(regex);
+         inter_sp = sp;
+         error("regmatch: result array too big");
+         /* NOTREACHED */
+         return NULL;
+     }
+     matches = allocate_array(found);
+     svp = matches->item;
+ 
+     /* put resulting strings in that array */
+     for (i = 0; i < found; i++) {
+ 
+         if (ergs[(2*i)+1] == -1) {
+             /* no match stored in this subpattern */
+             put_number(svp, 0);
+         }
+         else {
+             len = pcre_get_substring(text, ergs, found, i, &match);
+             if (len < 0) {
+                 /* This should never happen because memory problems
+                  * are handled by xalloc() */
+                 pcregex_free(regex);
+                 inter_sp = sp;
+                 error("regmatch: internal error");
+                 /* NOTREACHED */
+                 return NULL;
+             }
+ 
+             /* memory of match was allocated via pcre_malloc == xalloc
+              * should it be string_copy()ed?                             */
+             put_malloced_string(svp, (char*)match);
+         }
+ 
+         svp++;
+     }
+ 
+     pcregex_free(regex);
+     free_svalue(sp--);
+     free_string_svalue(sp--);
+     free_string_svalue(sp);
+ 
+     put_array(sp, matches);
+     return sp;
+ }
+ #endif /* USE_PCRE */
  
  /*-------------------------------------------------------------------------*/
  svalue_t *
diff -c /mud/src/driver/3-2-dev/src/func_spec ./func_spec
*** /mud/src/driver/3-2-dev/src/func_spec	Sat Jul 14 05:49:25 2001
--- ./func_spec	Thu Jul 26 22:57:33 2001
***************
*** 512,517 ****
--- 512,518 ----
  string  md5_encrypt(string);
  string *regexplode(string, string);
  string  regreplace(string,string,closure|string,int);
+ mixed  *regmatch(string, string, int);
  string  trim(string, ...);
  string  upper_case(string);
  
diff -c /mud/src/driver/3-2-dev/src/lex.c ./lex.c
*** /mud/src/driver/3-2-dev/src/lex.c	Sat Jul 14 05:49:25 2001
--- ./lex.c	Thu Jul 26 19:02:32 2001
***************
*** 792,797 ****
--- 792,800 ----
  #ifdef USE_DEPRECATED
      add_permanent_define("__DEPRECATED__", -1, string_copy(""), MY_FALSE);
  #endif
+ #ifdef USE_PCRE
+     add_permanent_define("__PCRE__", -1, string_copy(""), MY_FALSE);
+ #endif
      if (wizlist_name[0] != '\0')
      {
          if (compat_mode)
diff -c /mud/src/driver/3-2-dev/src/main.c ./main.c
*** /mud/src/driver/3-2-dev/src/main.c	Mon Jul 16 06:36:07 2001
--- ./main.c	Thu Jul 26 18:25:46 2001
***************
*** 190,195 ****
--- 190,198 ----
  #ifdef RXCACHE_TABLE
      rxcache_init();
  #endif
+ #ifdef USE_PCRE
+     pcre_init();
+ #endif
  
      put_number(&const0, 0);
      put_number(&const1, 1);
diff -c /mud/src/driver/3-2-dev/src/rxcache.c ./rxcache.c
*** /mud/src/driver/3-2-dev/src/rxcache.c	Thu May 17 05:08:31 2001
--- ./rxcache.c	Thu Jul 26 22:55:30 2001
***************
*** 54,59 ****
--- 54,113 ----
  
  #include "../mudlib/sys/debug_info.h"
  
+ #ifdef USE_PCRE
+ /*--------------------------------------------------------------------
+  * Wrapper functions for the pcre module following below:
+  */
+ 
+ static uint32 pcre_malloc_size;
+ static const char* pcre_malloc_err;
+ 
+ /* malloc wrapper for pcre package
+  */
+ void* pcre_wrapper_malloc(size_t size)  {
+     void* x;
+     xallocate(x, size, pcre_malloc_err);
+     if (!x) return NULL;
+     pcre_malloc_size += size;
+     return x;
+ }
+ 
+ void  pcre_wrapper_free(void *ptr)      { return xfree(ptr); }
+ 
+ /* Initialise the pcre memory management */
+ void pcre_init(void)
+ {
+     pcre_malloc = pcre_wrapper_malloc;
+     pcre_free   = pcre_wrapper_free;
+ }
+ 
+ /* generate apropriate error message for pcre_exec() calls */
+ const char* pcre_error_message(int found)
+ {
+     const char* text;
+     if (found > 0) return NULL;
+     switch (found) {
+         case 0:
+             text = "too many capturing parentheses"; break;
+         case PCRE_ERROR_NULL:
+             text = "code or subject NULL"; break;
+         case PCRE_ERROR_BADOPTION:
+             text = "unknown option specified"; break;
+         case PCRE_ERROR_BADMAGIC:
+             text = "regex memory invalid"; break;
+         case PCRE_ERROR_UNKNOWN_NODE:
+             text = "regex memory violated"; break;
+         case PCRE_ERROR_NOMEMORY:
+             text = "out of memory"; break;
+         default:
+             text = "unknown internal error"; break;
+     }
+     return text;
+ }
+ 
+ #endif /* USE_PCRE */
+ /*--------------------------------------------------------------------*/
+ 
  #ifdef RXCACHE_TABLE
  
  /*--------------------------------------------------------------------*/
***************
*** 66,84 ****
  #define RxStrHash(s) ((s) % RXCACHE_TABLE)
  #endif
  
- 
- /* One expression hashtable entry */
- 
- typedef struct RxHashEntry {
-     unsigned char * pString;  /* Generator string, a shared string
-                                * NULL if unused */
-     p_uint   hString;  /* Hash of pString */
-     Bool     from_ed;  /* The from_ed value */
-     Bool     excompat; /* The excompat value */
-     regexp * pRegexp;  /* The generated regular expression from regcomp() */
- } RxHashEntry;
- 
- 
  /* Variables */
  static RxHashEntry xtable[RXCACHE_TABLE];  /* The Expression Hashtable */
  
--- 120,125 ----
***************
*** 98,103 ****
--- 139,260 ----
      memset(xtable, 0, sizeof(xtable));
  }
  
+ #ifdef USE_PCRE
+ pcregex* pcregex_cache(const char* expr, int opt)
+ {
+     p_uint hExpr;
+     pcregex *pRegexp;
+     RxHashEntry *pHash;
+     const char* pErrmsg;
+     int erridx;
+ 
+     iNumXRequests++;
+ 
+     hExpr = whashstr((char *)expr, 50);
+     pHash = xtable+RxStrHash(hExpr);
+ 
+     /* Look for a ready-compiled regexp */
+     if (pHash->pString  != NULL
+      && pHash->hString  == hExpr
+      && pHash->pc       == 1
+      && !strcmp((char *)pHash->pString, (char *)expr)
+        )
+     {
+         iNumXFound++;
+         return pcregex_dup(pHash->pRegex.pc_re);
+     }
+ 
+     /* Regexp not found: compile a new one and enter it
+      * into the table.
+      */
+ 
+     xallocate(pRegexp, sizeof(pcregex), "rxcache entry");
+ 
+     pcre_malloc_size = 0;
+     pcre_malloc_err  = "compiling regex";
+     pRegexp->pProg  = pcre_compile(expr, opt, &pErrmsg, &erridx, NULL);
+ 
+     if (NULL == pRegexp->pProg) {
+         xfree(pRegexp);
+         error("pcre: %s at offset %d\n", pErrmsg, erridx);
+         /* NOTREACHED */
+         return NULL;
+     }
+ 
+     pcre_malloc_err  = "studying regex";
+     pRegexp->pHints = pcre_study(pRegexp->pProg, 0, &pErrmsg);
+ 
+     if (pErrmsg) {
+         xfree(pRegexp);
+         error("pcre: %s\n", pErrmsg);
+         /* NOTREACHED */
+         return NULL;
+     }
+ 
+     pRegexp->regalloc = pcre_malloc_size + sizeof(pRegexp);
+     pRegexp->refs     = 1;
+ 
+     expr = (unsigned char *)make_shared_string((char *)expr);
+ 
+     if (NULL != pHash->pString)
+     {
+         iNumXCollisions++;
+         free_string((char *)pHash->pString);
+ 
+         if (pHash->pc) pcregex_free(pHash->pRegex.pc_re);
+         else           rx_free(pHash->pRegex.ed_re);
+     }
+     pHash->pString      = (unsigned char *) expr; /* refs are transferred */
+     pHash->hString      = hExpr;
+     pHash->pRegex.pc_re = pRegexp;
+     pHash->from_ed      = 0; /* not used */
+     pHash->excompat     = 0; /* not used */
+     pHash->pc           = 1;
+ 
+     iNumXEntries++;
+     iXSizeAlloc += pRegexp->regalloc;
+ 
+     return pcregex_dup(pRegexp);
+ } /* pcregex_cache */
+ 
+ /*--------------------------------------------------------------------*/
+ 
+ pcregex *
+ pcregex_dup (pcregex * expr)
+ 
+ /* Increase the reference count of <expr> and return it.
+  */
+ 
+ {
+     expr->refs++;
+     return expr;
+ }
+ 
+ /*--------------------------------------------------------------------*/
+ 
+ void
+ pcregex_free (pcregex * expr)
+ 
+ /* Decrease the reference count of <expr>. If it reaches 0, the
+  * structure and all associated data is deallocated.
+  */
+ 
+ {
+     expr->refs--;
+     if (expr->refs) return;
+ 
+     iNumXEntries--;
+     iXSizeAlloc -= expr->regalloc;
+     if (expr->pHints) xfree(expr->pHints);
+     xfree(expr->pProg);
+     xfree(expr);
+ }
+ 
+ /*--------------------------------------------------------------------*/
+ 
+ 
+ #endif /* USE_PCRE */
+ 
  /*--------------------------------------------------------------------*/
  regexp *
  regcomp_cache(unsigned char * expr, Bool excompat, Bool from_ed)
***************
*** 123,137 ****
      pHash = xtable+RxStrHash(hExpr);
  
      /* Look for a ready-compiled regexp */
!     if (pHash->pString != NULL
!      && pHash->hString == hExpr
!      && pHash->from_ed == from_ed
       && pHash->excompat == excompat
       && !strcmp((char *)pHash->pString, (char *)expr)
         )
      {
          iNumXFound++;
!         return rx_dup(pHash->pRegexp);
      }
  
      /* Regexp not found: compile a new one and enter it
--- 280,295 ----
      pHash = xtable+RxStrHash(hExpr);
  
      /* Look for a ready-compiled regexp */
!     if (pHash->pString  != NULL
!      && pHash->hString  == hExpr
!      && pHash->from_ed  == from_ed
!      && pHash->pc       == 0
       && pHash->excompat == excompat
       && !strcmp((char *)pHash->pString, (char *)expr)
         )
      {
          iNumXFound++;
!         return rx_dup(pHash->pRegex.ed_re);
      }
  
      /* Regexp not found: compile a new one and enter it
***************
*** 147,162 ****
      {
          iNumXCollisions++;
          iNumXEntries--;
-         iXSizeAlloc -= pHash->pRegexp->regalloc;
  
          free_string((char *)pHash->pString);
!         rx_free(pHash->pRegexp);
      }
!     pHash->pString = expr; /* refs are transferred */
!     pHash->hString = hExpr;
!     pHash->pRegexp = pRegexp;
!     pHash->from_ed = from_ed;
!     pHash->excompat = excompat;
  
      iNumXEntries++;
      iXSizeAlloc += pRegexp->regalloc;
--- 305,321 ----
      {
          iNumXCollisions++;
          iNumXEntries--;
  
          free_string((char *)pHash->pString);
!         if (pHash->pc) pcregex_free(pHash->pRegex.pc_re);
!         else           rx_free(pHash->pRegex.ed_re);
      }
!     pHash->pString      = expr; /* refs are transferred */
!     pHash->hString      = hExpr;
!     pHash->pRegex.ed_re = pRegexp;
!     pHash->from_ed      = from_ed;
!     pHash->excompat     = excompat;
!     pHash->pc           = 0;
  
      iNumXEntries++;
      iXSizeAlloc += pRegexp->regalloc;
***************
*** 255,262 ****
  
  {
      expr->refs--;
!     if (!expr->refs)
!         xfree(expr);
  }
  
  /*--------------------------------------------------------------------*/
--- 414,424 ----
  
  {
      expr->refs--;
!     if (expr->refs) return;
! 
!     iNumXEntries--;
!     iXSizeAlloc -= expr->regalloc;
!     xfree(expr);
  }
  
  /*--------------------------------------------------------------------*/
***************
*** 276,282 ****
  
      for (i = 0; i < RXCACHE_TABLE; i++)
          if (NULL != xtable[i].pString)
!             xtable[i].pRegexp->refs = 0;
  } /* clear_rxcache_refs() */
  
  /*--------------------------------------------------------------------*/
--- 438,447 ----
  
      for (i = 0; i < RXCACHE_TABLE; i++)
          if (NULL != xtable[i].pString)
!         {
!             if (xtable[i].pc) xtable[i].pRegex.ed_re->refs = 0;
!             else              xtable[i].pRegex.pc_re->refs = 0;
!         }
  } /* clear_rxcache_refs() */
  
  /*--------------------------------------------------------------------*/
***************
*** 293,299 ****
          if (NULL != xtable[i].pString)
          {
              count_ref_from_string((char *)xtable[i].pString);
!             count_rxcache_ref(xtable[i].pRegexp);
          }
      } /* for (i) */
  
--- 458,475 ----
          if (NULL != xtable[i].pString)
          {
              count_ref_from_string((char *)xtable[i].pString);
!             if (xtable[i].pc)
!             {
!                 note_malloced_block_ref((char *)xtable[i].pRegex.pc_re);
!                 note_malloced_block_ref((char *)xtable[i].pRegex.pc_re->pProg);
!                 if (xtable[i].pRegex.pc_re->pHints)
!                     note_malloced_block_ref((char *)xtable[i].pRegex.pc_re->pHints);
!                 xtable[i].pRegex.pc_re->refs++;
!             } else
!             {
!                 note_malloced_block_ref((char *)xtable[i].pRegex.ed_re);
!                 xtable[i].pRegex.ed_re->refs++;
!             }
          }
      } /* for (i) */
  
***************
*** 305,311 ****
  
  /* Mark all memory associated with one regexp structure and count
   * the refs.
!  * This function is called both from rxcache as well as from ed.
   */
  
  {
--- 481,487 ----
  
  /* Mark all memory associated with one regexp structure and count
   * the refs.
!  * This function is called from ed.
   */
  
  {
***************
*** 313,321 ****
      pRegexp->refs++;
  } /* count_rxcache_ref() */
  
  #endif /* if GC_SUPPORT */
  
! #endif /* if RXCACHE_TABLE */
  
  /*====================================================================*/
  
--- 489,555 ----
      pRegexp->refs++;
  } /* count_rxcache_ref() */
  
+ /*--------------------------------------------------------------------*/
  #endif /* if GC_SUPPORT */
  
! #else /* RXCACHE_TABLE undef'd*/
! 
! /*--------------------------------------------------------------------*/
! /* Wrapper to use PCRE without cache */
! 
! #ifdef USE_PCRE
! pcregex* pcregex_cache(const char* expr, int opt)
! {
!     pcregex *pRegexp;
!     const char* pErrmsg;
!     int erridx;
! 
!     xallocate(pRegexp, sizeof(pcregex), "rxcache entry");
! 
!     pcre_malloc_size = 0;
!     pcre_malloc_err  = "compiling regex";
!     pRegexp->pProg  = pcre_compile(expr, opt, &pErrmsg, &erridx, NULL);
! 
!     if (NULL == pRegexp->pProg) {
!         xfree(pRegexp);
!         error("pcre: %s at offset %d\n", pErrmsg, erridx);
!         /* NOTREACHED */
!         return NULL;
!     }
! 
!     pcre_malloc_err  = "studying regex";
!     pRegexp->pHints = pcre_study(pRegexp->pProg, 0, &pErrmsg);
! 
!     if (pErrmsg) {
!         xfree(pRegexp);
!         error("pcre: %s\n", pErrmsg);
!         /* NOTREACHED */
!         return NULL;
!     }
! 
!     pRegexp->regalloc = pcre_malloc_size + sizeof(pRegexp);
!     pRegexp->refs     = 1;
! 
!     expr = (unsigned char *)make_shared_string((char *)expr);
! 
!     return pRegexp;
! }
! 
! /*--------------------------------------------------------------------*/
! 
! void
! pcregex_free (pcregex * expr)
! 
! /* Deallocate structure and all associated data
!  */
! 
! {
!     if (expr->pHints) xfree(expr->pHints);
!     xfree(expr->pProg);
!     xfree(expr);
! }
  
  /*====================================================================*/
  
+ #endif /* USE_PCRE */
+ #endif /* RXCACHE_TABLE undef'd */
diff -c /mud/src/driver/3-2-dev/src/rxcache.h ./rxcache.h
*** /mud/src/driver/3-2-dev/src/rxcache.h	Fri Feb 23 06:33:35 2001
--- ./rxcache.h	Thu Jul 26 20:42:43 2001
***************
*** 5,10 ****
--- 5,50 ----
  
  #include "regexp.h"
  #include "strfuns.h"
+ #include "pcre-3.4/pcre.h"
+ 
+ /* --- struct pcregex: regular expression basis ---
+  *
+  * This structure is used to hold a compiled regular expression as well
+  * as caching and refcounting data analog struct regexp
+  */
+ 
+ typedef struct pcregex {
+     pcre*         pProg;     /* The generated regular expression */
+     pcre_extra*   pHints;    /* Study data */
+     long          regalloc;  /* Allocated total length, used by rxcache */
+     p_uint        refs;      /* Number of refs, used+maintained by rxcache */
+ } pcregex;
+ 
+ /* --- struct RxHashEntry: One expression hashtable entry ---
+  *
+  * The rxcache table consists of this entries
+  */
+ 
+ typedef struct RxHashEntry {
+     unsigned char * pString;    /* Generator string, a shared string
+                                  * NULL if unused */
+     p_uint          hString;    /* Hash of pString */
+     Bool            from_ed;    /* The from_ed value */
+     Bool            excompat;   /* The excompat value */
+     Bool            pc;         /* Perl style regex? */
+     union {
+         regexp*     ed_re;      /* ed style regex program */
+         pcregex*    pc_re;      /* perl style regex program */
+     } pRegex;
+ } RxHashEntry;
+ 
+ #ifdef USE_PCRE
+ #define OVEC_LEN 300            /* is maximum, means 99 parentheses */
+ extern void pcregex_free (pcregex *);
+ extern pcregex * pcregex_dup (pcregex *);
+ pcregex* pcregex_cache(const char* expr, int opt);
+ const char* pcre_error_message(int);
+ #endif USE_PCRE
  
  #ifdef RXCACHE_TABLE
  
--311121419-828061240-996183711=:22388--