blob: 1659fe18338d2da0d040220ec0e7d34c20cc2739 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// player/commands.c -- alias, history and player command handling
4//
5// $Id: command.c 9576 2016-06-18 15:00:01Z Zesstra $
6#pragma strong_types
7#pragma save_types
8//#pragma range_check
9#pragma no_clone
10#pragma pedantic
11
12#define NEED_PROTOTYPES
13#include <player/command.h>
14#include <player/comm.h>
15#include <thing/properties.h>
16#include <living/moving.h>
17#include <player.h>
18#undef NEED_PROTOTYPES
19
20#include <properties.h>
21#include <language.h>
22#include <new_skills.h>
23#include <config.h>
24#include <defines.h>
25#include <wizlevels.h>
26#include <logging.h>
27#include <strings.h>
28
29#define CBLOG(x) log_file(SHELLLOG("DISABLECOMMANDS"),x,200000)
Zesstrafb4cc3d2019-05-06 21:16:30 +020030#define FALIASDB "/secure/zweities"
MG Mud User88f12472016-06-24 23:31:02 +020031
32#define HIST_SIZE 40
33#define EPMASTER "/secure/explorationmaster"
34
Zesstrafb4cc3d2019-05-06 21:16:30 +020035// Im Char gespeicherte Aliase
MG Mud User88f12472016-06-24 23:31:02 +020036private mapping aliases;
Zesstrafb4cc3d2019-05-06 21:16:30 +020037// Vereinigte Liste aktiver Aliase aus im Char gespeicherten und
38// Familienaliases. Wird nicht gespeichert, sondern bei Login erzeugt!
39private nosave mapping active_aliases = ([]);
40
MG Mud User88f12472016-06-24 23:31:02 +020041private string *commands;
42private int hist_size, show_processing, histmin;
43private string default_notify_fail;
44private nosave string *history, *unparsed_args, unmodified;
45private nosave int hist_now;
46private nosave object last_command_env;
47private nosave int cmds_per_time, last_chg, max_commands, *cmd_types;
48// Datenstruktur: ({Setzer, Ablaufzeit, String/Closure})
49private nosave mixed disablecommands;
50private nosave object* syntaxdb;
51
52nomask void __set_bb(int flag);
53
54static varargs int __auswerten(string str, string intern);
55varargs int SoulComm(string str, string _verb);
56varargs mixed More(string str, int fflag, string returnto);
MG Mud User88f12472016-06-24 23:31:02 +020057static void reallocate_histbuf();
58
59private void AddHistory(string str)
60{
61 if (!stringp(str) || str=="" || str[0]=='&' || str[0]=='^' ||
62 str=="hist")
63 return;
64 if (!hist_size) return;
65 if (!pointerp(history) || sizeof(history)!=hist_size)
66 reallocate_histbuf();
67 if (sizeof(str)>=histmin && history[(hist_size+hist_now-1)%hist_size]!=str)
68 history[(hist_now++)%hist_size]=str;
69}
70
71static void create()
72{
73 last_chg=0;
74 histmin=hist_now=0;
75 Set(P_LOCALCMDS,({}));
76 Set(P_LOCALCMDS,PROTECTED,F_MODE_AS);
77 Set("_syntaxdb", SECURED|SAVE, F_MODE_AS);
78
79 show_processing=1;
80 unparsed_args=({0,0,0});
81 hist_size=HIST_SIZE;
82}
83
84static int replacedisplay(string str)
85{
86 if (!str || str=="" || !sscanf(str,"%d",show_processing))
87 printf("Unzulaessige Eingabe!\n%s 0|1|2\n",query_verb());
88 printf("Ersetzungsanzeige auf Level %d.\nLevel 0: Nichts anzeigen\n"+
89 "Level 1: Nur History-Ersetzungen anzeigen\n"+
90 "Level 2: History- und Alias-Ersetzungen anzeigen\n",show_processing);
91 if (show_processing>2&&!IS_WIZARD(ME)) show_processing=2;
92 return 1;
93}
94
95static int histmin(string str)
96{
97 int len;
98
99 if (!str||!sscanf(str,"%d",len)||len<0)
100 {
101 write("Benutzung: histmin ZAHL\nLegt die Mindestlaenge fest, die eine \
102Befehlszeile haben muss, um in den\nHistory-Puffer zu gelangen. Derzeit \
103eingestellt auf "+(string)histmin+" Zeichen.\n");
104 return 1;
105 }
106 histmin=len;
107 write("Mindestlaenge auf "+(string)len+" eingestellt.\n");
108 return 1;
109}
110
111static void reallocate_histbuf()
112{
113 int i;
114
115 history=allocate(hist_size);
116 hist_now=0;
117 for (i=0;i<hist_size;i++)
118 if (!stringp(history[i]))
119 history[i]="\n\n";
120}
121
122static int histlen(string str)
123{
124 int d;
125 if (!str||!sscanf(str,"%d",d)||d<0||d>40)
126 {
127 write("Benutzung: histlen ZAHL\nZAHL muss zwischen 0 und 40 liegen.\n");
128 printf("Deine History-Buffer-Laenge liegt bei %d Befehlen.\n",hist_size);
129 return 1;
130 }
131 hist_size=d;
132 printf("Deine History-Buffer-Laenge liegt jetzt bei %d Befehlen.\n",
133 hist_size);
134 reallocate_histbuf();
135 return 1;
136}
137
Zesstrafb4cc3d2019-05-06 21:16:30 +0200138private void merge_family_aliases()
139{
140 // Char- und Familienaliase addieren.
141 // Die Aliase des Char haben Prioritaet und ueberdecken die der Familie.
142 active_aliases = FALIASDB->QueryFamilyAlias() + aliases;
143}
144
MG Mud User88f12472016-06-24 23:31:02 +0200145static void initialize()
146{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200147 if (!pointerp(history)||sizeof(history)!=hist_size)
148 reallocate_histbuf();
149 add_action("__auswerten","",1);
MG Mud User88f12472016-06-24 23:31:02 +0200150 max_commands = EPMASTER->QueryCommands();
151 cmd_types = EPMASTER->QueryCmdTypes() || ({});
152
153 if ( !mappingp(aliases) )
154 aliases = ([]);
155
Zesstrafb4cc3d2019-05-06 21:16:30 +0200156 merge_family_aliases();
157
MG Mud User88f12472016-06-24 23:31:02 +0200158 if ( !pointerp(commands) )
159 commands = ({});
160
161 if (QueryProp("_syntaxdb"))
162 syntaxdb = ({find_object("/secure/syntaxdb")});
163/* else if (QueryProp(P_TESTPLAYER))
164 {
165 SetProp("_syntaxdb", 1);
166 call_out(#'_notify, 2,
167 "\nDa Du als Testspieler markiert bist, wurde bei Dir "
168 "die Syntaxsammlung eingeschaltet. Du kannst dies "
169 "wieder ausschalten. (hilfe syntaxsammlung) "
170 "Es waere schoen, wenn Du es beim Testen von "
171 "Gebieten einschaltest.", 0);
172 }*/
173}
174
175static mixed _set_default_notify_fail(string s)
176{
177 if (stringp(s)&&s!="")
178 {
179 if (s[<1]!='\n') s+="\n";
180 return default_notify_fail=s;
181 }
182 else if (!s||s=="")
183 return (default_notify_fail=0);
184}
185
186static mixed _query_default_notify_fail()
187{
188 return default_notify_fail;
189}
190
191static int set_errormessage(string s)
192{
193 if (!(s=_unparsed_args()))
194 {
195 _set_default_notify_fail(0);
196 write("Standard-Fehlermeldung auf \"Wie bitte?\" gesetzt.\n");
197 } else
198 {
199 write(break_string(sprintf("Standard-Fehlermeldung auf %s gesetzt.\n",
200 s),78));
201 _set_default_notify_fail(s);
202 }
203 return 1;
204}
205
206void reconnect()
207{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200208 if (!mappingp(aliases))
209 aliases=([]);
210
211 merge_family_aliases();
MG Mud User88f12472016-06-24 23:31:02 +0200212
213 if ( !pointerp(commands) )
214 commands = ({});
215
216 max_commands = EPMASTER->QueryCommands();
217 cmd_types = EPMASTER->QueryCmdTypes() || ({});
218}
219
220static int show_hist()
221{
222 int i;
223 string comm;
224
225 tell_object( ME, "Die History-Liste enthaelt folgende Kommandos:\n" );
226
227 for( i = 0; i < hist_size; i++ )
228 if ((comm=history[(hist_now+i)% hist_size])!= "\n\n")
229 tell_object( ME, " &"+(hist_now+i-hist_size)+"/-"+ (hist_size-i-1)
230 +"\t= "+comm+"\n");
231 return 1;
232}
233
Zesstrafb4cc3d2019-05-06 21:16:30 +0200234static string present_alias(<string|int>* ali)
MG Mud User88f12472016-06-24 23:31:02 +0200235{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200236 int j;
237 <string|int> k;
MG Mud User88f12472016-06-24 23:31:02 +0200238 string s,s2;
239
240 for (s="",j=sizeof(ali)-1;j>=0;j--)
241 if (intp(ali[j]))
242 if ((k=ali[j])<0)
Zesstrafb4cc3d2019-05-06 21:16:30 +0200243 s="$"+(k==-1?"":(string)-k)+"*"+s;
MG Mud User88f12472016-06-24 23:31:02 +0200244 else
Zesstrafb4cc3d2019-05-06 21:16:30 +0200245 s="$"+(string)k+s;
MG Mud User88f12472016-06-24 23:31:02 +0200246 else
247 {
248 s2=implode(explode(ali[j],"\\"),"\\\\");
249 s=implode(explode(s2,"$"),"\\$")+s;
250 }
251 return s;
252}
253
254#define ALIFORMAT ({" %s\t= %s", "alias %s %s"})[display_as_aliascommand]
Zesstrafb4cc3d2019-05-06 21:16:30 +0200255#define FALIFORMAT ({" %s\t= %s", "alias -f %s %s"})[display_as_aliascommand]
MG Mud User88f12472016-06-24 23:31:02 +0200256// Ich weiss, den Variablennamen im define zu haben ist unfein, aber das
257// macht es im Code dann angenehm uebersichtlich. -HrT
258
Zesstrafb4cc3d2019-05-06 21:16:30 +0200259static int query_aliases(int display_as_aliascommand, int familymode)
MG Mud User88f12472016-06-24 23:31:02 +0200260{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200261 mapping selected_aliases;
MG Mud User88f12472016-06-24 23:31:02 +0200262
Zesstrafb4cc3d2019-05-06 21:16:30 +0200263 if (familymode)
264 selected_aliases=FALIASDB->QueryFamilyAlias();
265 else
266 selected_aliases = aliases;
267
Bugfix0c5133d2019-05-28 10:38:44 +0200268 string *alis = sort_array(m_indices(selected_aliases),#'>);
Zesstrafb4cc3d2019-05-06 21:16:30 +0200269
270 if(sizeof(alis))
MG Mud User88f12472016-06-24 23:31:02 +0200271 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200272 foreach(string a : &alis)
273 a = sprintf( (familymode ? FALIFORMAT : ALIFORMAT),
274 a, present_alias(selected_aliases[a]) );
275 More("Du hast folgende "
276 + (familymode ? "Familien-" : "")
Bugfix080e3ff2019-05-28 10:06:47 +0200277 + "Aliase definiert:\n" + CountUp(alis, "\n", "\n"));
MG Mud User88f12472016-06-24 23:31:02 +0200278 }
279 else
Zesstrafb4cc3d2019-05-06 21:16:30 +0200280 write("Du hast keine "
281 +(familymode ? "Familien-" : "") + "Aliase definiert.\n");
MG Mud User88f12472016-06-24 23:31:02 +0200282 return 1;
283}
284
MG Mud User88f12472016-06-24 23:31:02 +0200285static int alias(string str)
286{
Zesstraf86ed742019-04-25 18:37:27 +0200287 // unbearbeitetes Kommando ohne Verb ermitteln (auch ohne Trim an Anfang und
288 // Ende)
Zesstrafb4cc3d2019-05-06 21:16:30 +0200289 string um;
Zesstraf86ed742019-04-25 18:37:27 +0200290 if (unmodified && unmodified!="")
MG Mud User88f12472016-06-24 23:31:02 +0200291 um=implode(old_explode(unmodified," ")[1..]," ");
Zesstraf86ed742019-04-25 18:37:27 +0200292
MG Mud User88f12472016-06-24 23:31:02 +0200293 if (um=="") um=0;
Zesstraf86ed742019-04-25 18:37:27 +0200294 if( !(str = um||_unparsed_args()) || str=="*")
Zesstrafb4cc3d2019-05-06 21:16:30 +0200295 return query_aliases(0, 0);
MG Mud User88f12472016-06-24 23:31:02 +0200296
Zesstrafb4cc3d2019-05-06 21:16:30 +0200297 // optionen auswerten bis keine mehr kommen, dabei vorne den String
298 // verkuerzen
299 int display_as_aliascommand, familymode;
Zesstraf332ded2019-04-25 18:40:02 +0200300 while(sizeof(str) >= 2 && str[0] == '-')
301 {
302 if (str[1] == 'a')
303 display_as_aliascommand = 1;
304 else if (str[1] == 'f')
305 familymode = 1;
306 else
307 break;
308 // "-? " abschneiden
309 str = trim(str[2..], TRIM_LEFT);
MG Mud User88f12472016-06-24 23:31:02 +0200310 }
Zesstraf332ded2019-04-25 18:40:02 +0200311 if (!sizeof(str) || str=="*")
Zesstrafb4cc3d2019-05-06 21:16:30 +0200312 return query_aliases(display_as_aliascommand, familymode);
MG Mud User88f12472016-06-24 23:31:02 +0200313
Zesstrafb4cc3d2019-05-06 21:16:30 +0200314 int pos=member(str,' ');
Zesstraf86ed742019-04-25 18:37:27 +0200315 if (pos < 0) // Nur 1 Arg, Alias abfragen
MG Mud User88f12472016-06-24 23:31:02 +0200316 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200317 <string|int>* tmp;
318 if (familymode)
Bugfixc487d4c2019-05-28 11:04:29 +0200319 tmp=FALIASDB->QueryFamilyAlias(str)[str];
Zesstrafb4cc3d2019-05-06 21:16:30 +0200320 else
321 tmp=aliases[str];
322
323 if (tmp) // genau eins angegebenen
324 printf((familymode ? FALIFORMAT : ALIFORMAT)
325 +"\n",str,present_alias(tmp));
Zesstraf86ed742019-04-25 18:37:27 +0200326 else if (str[<1]=='*') // * am Ende, alle ausgeben, die passend anfangen
327 {
328 str=str[0..<2];
Zesstrafb4cc3d2019-05-06 21:16:30 +0200329 mapping selected_aliases;
330 if (familymode)
331 selected_aliases=FALIASDB->QueryFamilyAlias();
332 else
333 selected_aliases = aliases;
334 string *hits=filter(m_indices(selected_aliases),
335 function int (string alname, string start)
336 { return strstr(alname, start) == 0; },
337 str);
Zesstraf86ed742019-04-25 18:37:27 +0200338 if (!sizeof(hits))
MG Mud User88f12472016-06-24 23:31:02 +0200339 {
Zesstraf86ed742019-04-25 18:37:27 +0200340 printf("Du hast kein Alias, das mit \"%s\" anfaengt.\n", str);
341 return 1;
MG Mud User88f12472016-06-24 23:31:02 +0200342 }
Zesstraf86ed742019-04-25 18:37:27 +0200343 hits=sort_array(hits, #'>);
Zesstrafb4cc3d2019-05-06 21:16:30 +0200344 foreach(string hit: &hits)
345 hit = sprintf((familymode ? FALIFORMAT : ALIFORMAT),
346 hit, present_alias(selected_aliases[hit]));
Zesstraf86ed742019-04-25 18:37:27 +0200347 More("Folgende Aliase beginnen mit \""+str+"\":\n"+implode(hits,"\n"));
348 }
349 else // Nix gefunden
MG Mud User88f12472016-06-24 23:31:02 +0200350 printf("Du hast kein Alias \"%s\" definiert.\n",str);
351 return 1;
352 }
Zesstraf86ed742019-04-25 18:37:27 +0200353
MG Mud User88f12472016-06-24 23:31:02 +0200354 if (!pos)
355 {
Zesstraf86ed742019-04-25 18:37:27 +0200356 write("Fehler: Leerzeichen am Alias-Anfang\n");
MG Mud User88f12472016-06-24 23:31:02 +0200357 return 1;
358 }
Zesstraf86ed742019-04-25 18:37:27 +0200359 // Kommandoverb alles bis zum ersten " ".
Zesstrafb4cc3d2019-05-06 21:16:30 +0200360 string commandverb=str[0..pos-1];
Zesstraf86ed742019-04-25 18:37:27 +0200361 if (commandverb=="unalias")
MG Mud User88f12472016-06-24 23:31:02 +0200362 {
363 write
364 ("Es nicht moeglich, den Befehl unalias zu ueberladen (waer dumm :))\n");
365 return 1;
366 }
Zesstraf86ed742019-04-25 18:37:27 +0200367 if (commandverb=="*")
MG Mud User88f12472016-06-24 23:31:02 +0200368 {
369 write
370 ("Es nicht moeglich, den Befehl \"*\" zu ueberladen.\n");
371 return 1;
372 }
373
Zesstrafb4cc3d2019-05-06 21:16:30 +0200374 // ab hier wird der Expansionstext in ein Array von Strings geparst. Alle
375 // Alias-Argument ($n, $* oder $n*) stehen an der jeweiligen Stelle als
376 // laufender Index im Array. Negative Zahlen stehen fuer $n*, d.h. alle
377 // Argument nach dem genannten.
378 // Bsp: ({"stecke ", 1, " in ", -2 })
379 //TODO: regexplode("teile $1 mit $2* Ich bin jetzt weg, \$ verdienen!","[$][0-9][*]{0,1}",RE_PCRE)
380 str=str[pos+1..];
381 <string|int>* tmp=({}); // Alias-Array
382 int l, num;
MG Mud User88f12472016-06-24 23:31:02 +0200383 while (l=sizeof(str)) {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200384 pos=0; // Positionszaehler in str
385 int cont=1; // Statusflag fuer inneres while
386 while (cont)
387 {
388 // innere Schleife: scannt ein Argument und haengt es als Element in
389 // tmp an. Laeuft ueber den String bis Stringende oder & oder $
390 // erreicht wird, dann ist ein Argument vollstaendig und das naechste
391 // faengt an.
392 if (pos<l)
393 {
394 if(str[pos]=='\\') // escapte '\' werden zu einzelnen '\'.
395 {
MG Mud User88f12472016-06-24 23:31:02 +0200396 str=str[0..pos-1]+str[pos+1..];
397 l--;
Zesstrafb4cc3d2019-05-06 21:16:30 +0200398 }
399 else
400 {
401 if (str[pos]=='$' || str[pos]=='&') // & ist historisch...
402 { // Argument-Platzhalter gefunden
MG Mud User88f12472016-06-24 23:31:02 +0200403 cont=0;
Zesstrafb4cc3d2019-05-06 21:16:30 +0200404 if (pos>0) { // vorhergehender Textblock vollstaendig, anhaengen
MG Mud User88f12472016-06-24 23:31:02 +0200405 tmp+=({str[0..pos-1]});
406 }
407 if (pos==l-1) {
408 printf("Fehler: %c am Zeilenende\n",str[pos]);
409 return 1;
410 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200411 // $* oder $n ? Im Falle von $n landet in num der ASCII-Wert des
412 // Zeichens, von welchem der Wert von '0' abgezogen wird -> num
413 // enthaelt danach 0..9, wenn eine Ziffer angegeben wurde.
414 num=str[++pos]; // naechstes Zeichen holen
415 if (num=='*') {
416 // Argument 1 und pos muss wieder eins zurueck.
MG Mud User88f12472016-06-24 23:31:02 +0200417 num=1;
418 pos--;
419 } else {
420 num-='0';
421 }
422 if (num<0 || num>9) {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200423 printf("Fehler: Nach %c muss eine Ziffer oder * folgen\n",
MG Mud User88f12472016-06-24 23:31:02 +0200424 str[pos-1]);
425 return 1;
426 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200427 // str nach Argumentkennung weiter verarbeiten.
428 str=str[pos+1..];
429 // Aber fuer den Fall $n* das naechste Zeichen auch untersuchen
430 if (sizeof(str) && str[0]=='*') {
431 str=str[1..]; // auch ueberspringen
432 num = negate(num); // Im Array negiert kodieren
MG Mud User88f12472016-06-24 23:31:02 +0200433 }
434 tmp+=({num});
435 }
436 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200437 ++pos; // naechstes Zeichen im naechste inner while angucken
MG Mud User88f12472016-06-24 23:31:02 +0200438 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200439 // Ende des gesamten Strings erreicht.
440 else
441 {
442 cont=0; // ende inner while
443 // letzten Argumentblock anhaengen
444 if (str!="") tmp+=({str});
445 str=""; // beendet outer while
446 }
447 } // inner while
448 } // outer while
449
450 if (familymode)
451 {
452 int err=FALIASDB->AddOrReplaceFamilyAlias(commandverb, tmp);
453 if (err < 1)
454 {
455 printf("Neues Familienalias konnte nicht definiert werden.\n");
456 if (err==-2)
457 printf("Du hast schon genuegend Aliase definiert!\n");
458 }
459 else
460 {
461 printf("Neues Familienalias: %s\t= %s\n",
462 commandverb, present_alias(tmp));
463 // Alias direkt aktivieren, aber nur falls es keins in diesem Char gibt
464 // (was dann eh schon aktiv ist).
465 if (!member(aliases, commandverb))
466 active_aliases[commandverb] = tmp;
MG Mud User88f12472016-06-24 23:31:02 +0200467 }
468 }
MG Mud User88f12472016-06-24 23:31:02 +0200469 else
470 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200471 if ((!aliases[commandverb]) && (sizeof(aliases)>2000))
472 printf("Du hast schon genuegend Aliase definiert!\n");
473 else
474 {
Zesstrac687e292019-05-28 22:43:11 +0200475 if (member(active_aliases, commandverb)
476 && !member(aliases, commandverb))
477 printf("Hinweis: das neue Alias ueberschattet ein Familienalias.\n");
478 aliases[commandverb] = tmp;
Zesstrafb4cc3d2019-05-06 21:16:30 +0200479 active_aliases[commandverb] = tmp;
480 printf("Neues Alias: %s\t= %s\n",commandverb, present_alias(tmp));
481 }
MG Mud User88f12472016-06-24 23:31:02 +0200482 }
483 return 1;
484}
485
486static int unalias(string str) {
MG Mud User88f12472016-06-24 23:31:02 +0200487
Zesstrafb4cc3d2019-05-06 21:16:30 +0200488 string um;
MG Mud User88f12472016-06-24 23:31:02 +0200489 if (unmodified&&unmodified!="")
490 um=implode(old_explode(unmodified," ")[1..]," ");
491 if (um=="") um=0;
Zesstraf86ed742019-04-25 18:37:27 +0200492 if ( !(str=um || _unparsed_args()))
493 return 0;
494
Zesstrafb4cc3d2019-05-06 21:16:30 +0200495 int familymode;
Zesstraf332ded2019-04-25 18:40:02 +0200496 while(sizeof(str) >= 2 && str[0] == '-')
497 {
498 if (str[1] == 'f')
499 familymode = 1;
500 else
501 break;
502 // "-f " abschneiden
503 str = trim(str[2..], TRIM_LEFT);
504 }
505
MG Mud User88f12472016-06-24 23:31:02 +0200506 if (str == "*.*" || str == "*") {
507 write(break_string(
508 "Versuchs mal mit 'unalias .*', wenn Du wirklich alle Alias entfernen "
509 "willst.",78));
510 return 1;
511 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200512
513 mapping selected_aliases;
514 if (familymode)
515 selected_aliases=FALIASDB->QueryFamilyAlias();
516 else
517 selected_aliases = aliases;
518
519 string *to_delete;
520 // Genau ein Alias gegeben?
521 if (member(selected_aliases,str))
522 to_delete = ({str});
523 else // sonst als RegExp interpretieren
524 to_delete=regexp(m_indices(selected_aliases),("^"+str+"$"));
525
526 if (sizeof(to_delete))
Zesstraf86ed742019-04-25 18:37:27 +0200527 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200528 foreach(string key : to_delete)
Zesstraf86ed742019-04-25 18:37:27 +0200529 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200530 if (familymode)
531 FALIASDB->DeleteFamilyAlias(key);
532 else
533 m_delete(aliases, key);
534 // auf jeden Fall noch deaktivieren
535 m_delete(active_aliases, key);
MG Mud User88f12472016-06-24 23:31:02 +0200536 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200537 if (sizeof(to_delete) == 1)
538 write("Du entfernst das Alias \""+ to_delete[0] +"\".\n");
539 else
540 write(break_string(("Du entfernst folgende Aliase: "
541 +CountUp(to_delete) + ".\n"),75));
MG Mud User88f12472016-06-24 23:31:02 +0200542 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200543 else
544 write("So ein Alias hast Du nicht definiert.\n");
545
MG Mud User88f12472016-06-24 23:31:02 +0200546 return 1;
547}
548
549varargs string _unparsed_args(int level)
550{
551 return unparsed_args[level];
552}
553
554#define ARTIKEL ({"das","der","die","des","dem","den","ein","eine","einer",\
555 "eines"})
556
557#define TRENNER ({"in","aus","ueber","auf","unter","mit","durch","fuer",\
558 "von","vom","im","aufs","ein","weg","zurueck"})
559
560static string _single_spaces(string str)
561{
562 return regreplace(str, " *", " ", 1);
563}
564
565static mixed _return_args(string str)
566{
567 string *t,*t2,verb,s2;
568 int i,l,j,l2;
569
570 t=explode(trim(str,TRIM_BOTH)," ");
571 verb=t[0];
572 t = t[1..];
573 if (!sizeof(t))
574 {
575 unparsed_args[0]=unparsed_args[1]=unparsed_args[2]=0;
576 return str=verb;
577 }
578 else
579 str = unparsed_args[0] = implode(t, " ");
580
581 str=unparsed_args[1]=lower_case(_single_spaces(str));
582 t=regexplode(str,"\\<im\\>|\\<ins\\>");
583 for (i=1;i<sizeof(t);i+=2) t[i]="in";
584 t=regexplode(implode(t,""),"[\\,\\!\\:][\\,\\!\\:]*");
585 l=sizeof(t);
586 for(i=1;i<l;i+=2) t[i]="";
587 t=old_explode(implode(t,"")," ")-({""});
588 for (i=sizeof(t)-2;i>=0;i--)
589 {
590 if (member(ARTIKEL,t[i])>=0)
591 t=t[0..i-1]+t[i+1..];
592 }
593 unparsed_args[2]=implode(t," ");
594 t=regexplode((str=implode(t," ")),"[0-9][0-9]*\\.");
595 if ((l=sizeof(t))>2)
596 {
597 i=1;
598 while (i<l-1)
599 {
600 t[i]=" "+t[i][0..<2]+" ";
601 if ((l2=sizeof(t2=old_explode(t[i+1]," ")))<2)
602 t[i+1]+=t[i];
603 else
604 {
605 for (j=1;j<l2;j++)
606 {
607 if (member(TRENNER,t2[j])>=0)
608 {
609 t2[j-1]+=t[i];
610 l2=0;
611 }
612 }
613 if (!l2)
614 t[i+1]=implode(t2," ");
615 else
616 t[i+1]+=t[i];
617 }
618 t[i]="";
619 i+=2;
620 }
621 str=_single_spaces(verb+" "+implode(t," "));
622 if (str[<1]==' ') str=str[0..<2];
623 } else str=verb+(str==""?"":" "+str);
624 if (show_processing>2)
625 printf("-> {%s}\n",str);
626 return str;
627}
628
629static void decay_average()
630{
631 if (absolute_hb_count()-last_chg>14)
632 {
633 last_chg=absolute_hb_count()-last_chg;
634 if (last_chg>3000)
635 last_chg=absolute_hb_count(),cmds_per_time=0;
636 else
637 {
638 while (last_chg>14)
639 cmds_per_time=cmds_per_time*9/10, last_chg-=15;
640 last_chg=absolute_hb_count()-last_chg;
641 }
642 }
643}
644
645private void DelayPreparedSpells() {
646 mixed ps;
647
648 if (pointerp(ps=QueryProp(P_PREPARED_SPELL))
649 && sizeof(ps)>=1 && intp(ps[0])) {
650 ps[0]++;
651 SetProp(P_PREPARED_SPELL,ps);
652 write("Die Ausfuehrung Deines vorbereiteten Spruches wird verzoegert.\n");
653 } else if (ps) {
654 SetProp(P_PREPARED_SPELL,0);
655 }
656}
657
658static mixed bb;
659#ifndef BBMASTER
660#define BBMASTER "/secure/bbmaster"
661#endif
662
663/** Interpretiert Aliase und History-Kommandos
664 Eigentlich muesste hier noch die Umwandlung der Sonderzeichen
665 verschiedener Zeichensaetze mit convert_charset gemacht werden,
666 aber noch gibt es keine Moeglichkeit, den vom Spieler genutzten
667 Zeichensatz zu identifizieren.
668 \param[in] str string - Kommando des Spielers
669 \return interpretiertes Alias bzw. korrektes Kommando aus der History
670*/
671private string parsecommand(string str)
672{
673 if (str[0]=='\\')
674 {
675 // Kommando soll nicht interpretiert werden
676 return str[1..];
677 }
678 else if (str[0]=='&')
679 {
680 // Kommando aus der History
681 string cmd = str[1..];
682 int cmd_size = sizeof(cmd);
683 int cmd_found = 0;
684 if (cmd_size)
685 {
686 // Test ob &<text> etwas findet
687 for (int i=0;i<hist_size-1 && !cmd_found;i++)
688 {
689 int idx = (hist_size-i+hist_now-1)%hist_size;
690 if (history[idx][0..cmd_size-1]==cmd)
691 {
692 str = history[idx];
693 cmd_found = 1;
694 }
695 if (cmd_found)
696 {
697 if (show_processing)
698 printf("[%s]\n",str);
699 }
700 }
701 }
702 if (!cmd_found)
703 {
704 // Test, ob &<nr> klappt
705 int nummer;
706 if (str=="&&")
707 str = "&-0";
708 if (sscanf(str,"&%d",nummer))
709 {
710 if (nummer<0 || (!nummer && str[1]=='-'))
711 {
712 if (nummer<-(hist_size-1))
713 nummer=-1;
714 else
715 nummer=(hist_now+nummer-1+hist_size)%hist_size;
716 }
717 else
718 {
719 if (nummer>hist_now || hist_now-nummer>hist_size)
720 nummer=-1;
721 else
722 nummer=nummer%hist_size;
723 }
724 if (nummer<0
725 || ( (cmd=history[nummer]) =="\n\n") )
726 notify_fail("Der Befehl ist nicht in der History!\n");
727 else
728 {
729 str = cmd;
730 if (show_processing)
731 printf("[%s]\n",str);
732 }
733 }
734 }
735 }
736 switch (str)
737 {
738 case "n": return "norden";
739 case "s": return "sueden";
740 case "w": return "westen";
741 case "o": return "osten";
742 case "nw": return "nordwesten";
743 case "sw": return "suedwesten";
744 case "so": return "suedosten";
745 case "no": return "nordosten";
746 case "ob": return "oben";
747 case "u": return "unten";
748 }
749 // Test auf Alias
750 string output = "";
751 string* input = explode(str," ");
752 int input_size = sizeof(input);
Zesstrafb4cc3d2019-05-06 21:16:30 +0200753 mixed alias = active_aliases[input[0]];
MG Mud User88f12472016-06-24 23:31:02 +0200754 if (!alias)
755 return str;
Zesstrafb4cc3d2019-05-06 21:16:30 +0200756 // Das Alias ist in ein Array von Strings gespeichert. Alle
757 // Alias-Argument ($n, $* oder $n*) stehen an der jeweiligen Stelle als
758 // laufender Index im Array. An der Stelle werden die Argumente vom Alias
759 // eingefuegt, alle anderen Elemente werden in den output kopiert. Negative
760 // Zahlen stehen fuer $n*, d.h. alle Argument nach dem genannten.
761 // Bsp: ({"stecke ", 1, " in ", -2 })
MG Mud User88f12472016-06-24 23:31:02 +0200762 foreach (mixed a:alias)
763 {
764 if (!intp(a))
765 output += a;
766 else
767 {
768 if (a >= 0)
769 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200770 // Einzelnes Argument ($n). Argument anstelle von a einfuegen, falls
771 // genug angegeben wurden
MG Mud User88f12472016-06-24 23:31:02 +0200772 if (input_size > a)
773 output += input[a];
774 }
775 else
776 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200777 // Argumente ab n ($n*). Alle von a bis Ende einfuegen.
MG Mud User88f12472016-06-24 23:31:02 +0200778 a = -a;
779 if (input_size > a)
780 output += implode(input[a..]," ");
781 }
782 }
783 }
784 output = _single_spaces(output);
785 str = trim(output,TRIM_RIGHT);
786 if (show_processing>1)
787 printf("[%s]\n",str);
788 return str;
789}
790
791/** Behandelt alle Sonderfaelle der Eingabe des Spielers
792 Alle Befehle des Spielers, die nicht durch Objekte behandelt
793 werden sollen, werden hier erkannt und ausgefuehrt.
794 Dazu gehoert auch die Interpretation von Aliases und History-
795 befehlen.
796 \param[in] str string: Kommando des Spielers
797 \return auszufuehrendes Kommando
798 oder 0 fuer ein nicht interpretierbares Kommando
799 oder 1 fuer ein bereits durchgefuehrtes Kommando
800*/
801mixed modify_command(string str)
802{
803
804 if (extern_call() && previous_object() &&
805 (previous_object()!=this_object() || process_call()) )
806 {
807 return 0;
808 }
809
810 // Leerzeichen an den Enden abschneiden.
811 str = trim(str, TRIM_BOTH);
812
813 if (bb)
814 BBMASTER->BBWrite(trim(str,TRIM_RIGHT,"\n"), 0);
815
816 decay_average();
817 cmds_per_time+=10000;
818
819 unparsed_args[0]=unparsed_args[1]=unparsed_args[2]=unmodified="";
820
821 if (!sizeof(str)) return "";
822
823 // Kommando wird geparst
824 unmodified=parsecommand(str);
825
826 // Environment schonmal merken.
827 last_command_env=environment();
828
829 if (unmodified == "")
830 return "";
831 // Kommando in History merken, auch wenn es im Kommandoblock abgebrochen
832 // wird.
833 AddHistory(unmodified);
834
835 // pruefen, ob Kommandoblock gesetzt ist.
836 // (Fuer Magier mit mschau ein wird das ignoriert.)
837 // BTW: Es wird absichtlich nicht das Ergebnis der Closure zurueckgegeben,
838 // sonst wuerde man beliebigen Objekten nicht nur das Abbrechen, sondern
839 // auch das Aendern von Kommandos ermoeglichen.
840 if (disablecommands && !IS_LEARNING(ME) )
841 {
842 if (disablecommands[B_TIME] >= time()
843 && objectp(disablecommands[B_OBJECT]))
844 {
845 // disablecommands valid
846 // hart-kodierte Ausnameliste pruefen
847 if ( member(({"mrufe","mschau","bug","idee","typo","detail"}),
848 explode(str," ")[0]) == -1)
849 {
850 if (closurep(disablecommands[B_VALUE]))
851 {
852 if (funcall(disablecommands[B_VALUE],_return_args(unmodified)))
853 {
854 // Non-zero Closure-Ergebnis, Abbruch. Die gerufene Funktion ist
855 // fuer eine geeignete Meldung an den Spieler verantwortlich.
856 return 1;
857 }
858 }
859 // wenn Text, dann auch pruefen, ob das Kommandoverb in den Ausnahmen
860 // steht. (query_verb() geht leider hier noch nicht.)
861 else if (stringp(disablecommands[B_VALUE])
862 && member(disablecommands[B_EXCEPTIONS],
863 explode(str," ")[0]) == -1)
864 {
865 // meldung ausgeben...
866 tell_object(PL, disablecommands[B_VALUE]);
867 // und Ende...
868 return 1;
869 }
870 }
871 }
872 else disablecommands=0;
873 }
874
875 // Verfolger direkt ins Env reinholen.
876 if (remove_call_out("TakeFollowers")>=0)
877 catch(TakeFollowers();publish);
878
879 DelayPreparedSpells();
880
881 // Historyeintrag korrigieren
882 if (unmodified[0]=='^')
883 {
884 string *oldnew,pre,post;
885 if (sizeof(oldnew=explode(unmodified,"^"))>2)
886 {
887 int hist_idx = (hist_now-1)%hist_size;
888 sscanf(history[hist_idx],"%s"+oldnew[1]+"%s", pre, post);
889 unmodified = pre+oldnew[2]+post;
890 if (show_processing)
891 write("["+unmodified+"]\n");
892 // korrigiertes Kommando natuerlich auch in die History.
893 AddHistory(unmodified);
894 }
895 }
896
897 if( bb )
898 BBMASTER->BBWrite(" -> " + unmodified, 1);
899
900 if (show_processing>1)
901 printf("[%s]\n",unmodified);
902
903 mixed ret = _return_args(unmodified);
904
905 // wenn Spieler eingewilligt hat und die SyntaxDB geladen ist, Befehl
906 // dorthin melden.
907 if (syntaxdb)
908 {
909 if (!objectp(syntaxdb[0]))
910 syntaxdb[0] = find_object("/secure/syntaxdb");
911 if (syntaxdb[0])
912 catch(syntaxdb[0]->start_cmd(unmodified);nolog);
913 }
914 return ret;
915}
916
917static int do_list(string str)
918{
919 string *cmdlist;
920 int i;
921
922 if (!QueryProp(P_WANTS_TO_LEARN))
923 return 0;
924 cmdlist=old_explode(_unparsed_args()||"",";")-({ "" });
925 for (i=0;i<sizeof(cmdlist);i++)
926 {
927 cmdlist[i]=implode(old_explode(cmdlist[i]," ")-({}), " ");
928 if (show_processing)
929 write("["+cmdlist[i]+"]\n");
930 command(cmdlist[i]);
931 }
932 return 1;
933}
934
935//falls die aliasliste kaputt ist ...
936
937int unalias_all()
938{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200939 if (IS_ELDER(this_interactive()))
940 {
941 aliases=([]);
942 merge_family_aliases();
943 }
MG Mud User88f12472016-06-24 23:31:02 +0200944 return 1;
945}
946
947object _query_last_command_env()
948{
949 return last_command_env;
950}
951
952int _query_show_alias_processing()
953{
954 return show_processing;
955}
956
957int _query_histmin()
958{
959 return histmin;
960}
961
962varargs void AddAction(mixed fun, mixed cmd, int flag, int lvl)
963{
964 int i;
965 mixed *cmds;
966
967 log_file( "ARCH/ADD_ACTION", sprintf(
968 "%s:\n TO: %O TP: %O PO: %O\n fun: %O cmd: %O flag: %O lvl: %O",
969 dtime(time()), this_object(), this_player(), previous_object(),
970 fun, cmd, flag, lvl));
971
972 if (!(cmds=Query(P_LOCALCMDS))) cmds=({});
973
974 if (!pointerp(cmd)) cmd=({cmd});
975
976 for (i = sizeof(cmd)-1; i>=0; i--)
977 cmds += ({({ cmd[i] , fun, flag, lvl})});
978
979 Set(P_LOCALCMDS, cmds);
980}
981
982static int auswerten(mixed cmd, string str)
983{
984 if (closurep(cmd))
985 return funcall(cmd,str);
986 if (stringp(cmd))
987 return call_other(this_object(),cmd,str);
988 return 0;
989}
990
991static varargs int __auswerten(string str, string intern)
992{
993 string verb;
994 mixed *cmd, cmds;
995 int i,ret,lvl,l,vl;
996
997 if (!intern)
998 verb=query_verb();
999 else
1000 verb=intern;
1001 lvl=query_wiz_level(ME);
1002 vl=sizeof(verb);
1003 cmds=QueryProp(P_LOCALCMDS);
1004
1005 for(i=sizeof(cmds)-1;i>=0;i--)
1006 {
1007 cmd=cmds[i],l=sizeof(cmd[0]);
1008 if (cmd[0]==verb[0..l-1] && cmd[3]<=lvl && (cmd[2]||vl==l) &&
1009 (ret=auswerten(cmd[1],str)))
1010 return ret;
1011 }
1012 // An dieser Stelle gibt es hier und vermutlich nirgendwo anders etwas, was
1013 // dieses Kommando als gueltig betrachtet. Wir informieren ggf. die
1014 // Syntax-DB. (Achtung: wenn jemand ne add_action() im Spielerobjekt
1015 // einbaut, die vor dieser eingetragen wird, ist die Annahme ggf. falsch.)
1016 // wenn Spieler eingewilligt hat und die SyntaxDB geladen ist, Befehl
1017 // dorthin melden.
1018 if (syntaxdb)
1019 {
1020 if (!objectp(syntaxdb[0]))
1021 syntaxdb[0] = find_object("/secure/syntaxdb");
1022 if (syntaxdb[0])
1023 catch(syntaxdb[0]->cmd_unsuccessful();nolog);
1024 }
1025
1026 return 0;
1027}
1028
1029public void syntax_log_ep(int type)
1030{
1031 // wenn Spieler eingewilligt hat und die SyntaxDB geladen ist, Befehl
1032 // dorthin melden.
1033 if (syntaxdb && syntaxdb[0])
1034 {
1035 catch(syntaxdb[0]->LogEP(type);nolog);
1036 }
1037}
1038
1039static mixed _query_localcmds()
1040{
1041 mixed *l;
1042
1043 l=Query(P_LOCALCMDS);
1044 if (!pointerp(l))
1045 l=({});
1046 return ({
1047 ({"ali","alias",0,0}),
1048 ({"alias","alias",0,0}),
1049 ({"unali","unalias",1,0}),
1050 ({"histmin","histmin",0,0}),
1051 ({"histlen","histlen",0,0}),
1052 ({"hist","show_hist",0,0}),
1053 ({"history","show_hist",0,0}),
1054 ({"do","do_list",0,LEARNER_LVL}),
1055 ({"ersetzungsanzeige","replacedisplay",0,0}),
1056 ({"syntaxsammlung","collect_cmds",0,0}),
1057 ({"fehlermeldung","set_errormessage",0,SEER_LVL}),
1058 })+l;
1059}
1060
1061static int collect_cmds(string cmd)
1062{
1063 if (!stringp(cmd))
1064 {
1065 _notify("Mit diesem Befehl kannst Du mithelfen, Syntaxen im MG zu "
1066 "verbessern. Wenn Du einverstanden bist, speichern wir "
1067 "anonym (d.h. ohne Deinen Charnamen), welche Deiner Befehle "
1068 "erfolgreich und nicht erfolgreich waren. Uebliche "
1069 "Kommunikationsbefehle werden dabei nicht gespeichert.",
1070 0);
1071 _notify("Mit 'syntaxsammlung ja' kannst Du die Speicherung einschalten, "
1072 "mit 'syntaxsammlung nein' kannst Du sie ausschalten.",0);
1073 _notify("Deine Befehle werden zur Zeit"
1074 + (QueryProp("_syntaxdb") ? " " : " NICHT ")
1075 + "gespeichert.", 0);
1076 }
1077 else if (cmd == "ja")
1078 {
1079 SetProp("_syntaxdb", 1);
1080 _notify("Ab jetzt werden Deine Befehle gespeichert. Vielen Dank!", 0);
1081 }
1082 else
1083 {
1084 SetProp("_syntaxdb", 0);
1085 _notify("Ab jetzt werden Deine Befehle NICHT gespeichert.", 0);
1086 }
1087 return 1;
1088}
1089
1090int _query_command_average()
1091{
1092 decay_average();
1093 return cmds_per_time;
1094}
1095
1096nomask void __set_bb(int flag) {
1097 if( previous_object()!=find_object(BBMASTER) || process_call() )
1098 return;
1099 bb=flag;
1100}
1101
1102
1103nomask public void countCmds( int type, string key )
1104{
1105 string tmp;
1106
1107 if ( this_player() != this_interactive()
1108 || this_interactive() != this_object()
1109 || member( cmd_types, type ) < 0 )
1110 return;
1111
1112 tmp = sprintf( "%d\n%s", type, key );
1113
1114 commands -= ({ tmp });
1115 commands += ({ tmp });
1116 commands = commands[0..max_commands-1];
1117}
1118
1119
1120nomask public string *getCmds()
1121{
1122 string *tmp;
1123
1124 if ( previous_object() != find_object(BBMASTER) )
1125 return ({});
1126
1127 tmp = commands;
1128 commands = ({});
1129
1130 return tmp;
1131}
1132
1133/*
1134 * Force the monster to do a command. The force_us() function isn't
1135 * always good, because it checks the level of the caller, and this function
1136 * can be called by a room.
1137 */
1138int command_me(string cmd)
1139{
1140 if (IS_LEARNER(ME))
1141 {
1142 if (!this_interactive() || !previous_object())
1143 return 0;
1144 if( geteuid(ME)!=geteuid(this_interactive())
1145 || geteuid(ME)!=geteuid(previous_object()) )
1146 {
1147 if( query_wiz_level(ME)<query_wiz_level(previous_object()))
1148 tell_object(ME,previous_object()->name()+" zwingt Dich zu: "
1149 + cmd + ".\n");
1150 else
1151 {
1152 tell_object(ME,previous_object()->name()
1153 + " versucht, Dich zu " + cmd + " zu zwingen.\n" );
1154 return 0;
1155 }
1156 }
1157 }
1158 return command(cmd);
1159}
1160
1161
1162static mixed _query_p_lib_disablecommands() {
1163 // abgelaufen oder Objekt zerstoert? Weg damit.
1164 if (pointerp(disablecommands)
1165 && (disablecommands[B_TIME] < time()
1166 || !objectp(disablecommands[B_OBJECT])) )
1167 return(disablecommands = 0);
1168
1169 // sonst Kopie zurueck (copy(0) geht)
1170 return(copy(disablecommands));
1171}
1172
1173static mixed _set_p_lib_disablecommands(mixed data) {
1174
1175 // setzendes Objekt ermitteln, da diese Funktion nur per SetProp() gerufen
1176 // werden sollte (!), ist das PO(1);
1177 object origin = previous_object(1);
1178 // wenn nicht existent, direkt abbruch
1179 if (!objectp(origin))
1180 return _query_p_lib_disablecommands();
1181
1182 // Prop loeschen? Explizit loeschen darf jeder, allerdings nicht direkt
1183 // ungeprueft ueberschreiben.
1184 if (!data) {
1185 return (disablecommands = 0 );
1186 }
1187 // mal direkt buggen bei falschen Datentyp, damits auffaellt.
1188 if (!pointerp(data) || sizeof(data) < 2 || !intp(data[0])
1189 || (!stringp(data[1]) && !closurep(data[1]))
1190 || (sizeof(data) >= 3 && !pointerp(data[2])) )
1191 raise_error(sprintf(
1192 "Wrong data type for P_DISABLE_COMMANDS. Expected Array with "
1193 "2 or 3 elements (int, string|closure, [string*]), got %.25O\n",
1194 data));
1195
1196 // Wenn abgelaufen oder gleiches Objekt wie letztes Mal: eintragen.
1197 if (!disablecommands || (disablecommands[B_TIME] < time()
1198 || !objectp(disablecommands[B_OBJECT])
1199 || disablecommands[B_OBJECT] == origin) ) {
1200 // Loggen nur, wenn eine Closure eingetragen wird. Reduziert den
1201 // Logscroll und Strings haben deutlich weniger Missbrauchspotential.
1202 if (closurep(data[1])) {
1203 CBLOG(sprintf("[%s] CB gesetzt von %O, gueltig bis %s, Daten: %O\n",
1204 strftime("%Y%m%d-%H:%M:%S"),origin,
1205 strftime("%Y%m%d-%H:%M:%S",data[0]),
1206 (stringp(data[1]) ? regreplace(data[1],"\n","\\n",0)
1207 : data[1])));
1208 }
1209 if (sizeof(data)+1 <= B_EXCEPTIONS)
1210 disablecommands = ({ origin, data[0], data[1], ({}) });
1211 else
1212 disablecommands = ({ origin, data[0], data[1], data[2] });
1213 return(copy(disablecommands));
1214 }
1215
1216 return(_query_p_lib_disablecommands());
1217}
1218
1219static mixed _set__syntaxdb(mixed v)
1220{
1221 Set("_syntaxdb", v, F_VALUE);
1222 if (v)
1223 syntaxdb = ({find_object("/secure/syntaxdb")});
1224 else
1225 syntaxdb = 0;
1226 return QueryProp("_syntaxdb");
1227}
1228