blob: 2220143c034602bc94513aa22c76defbf957db00 [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 {
475 aliases[commandverb]=tmp;
476 active_aliases[commandverb] = tmp;
477 printf("Neues Alias: %s\t= %s\n",commandverb, present_alias(tmp));
478 }
MG Mud User88f12472016-06-24 23:31:02 +0200479 }
480 return 1;
481}
482
483static int unalias(string str) {
MG Mud User88f12472016-06-24 23:31:02 +0200484
Zesstrafb4cc3d2019-05-06 21:16:30 +0200485 string um;
MG Mud User88f12472016-06-24 23:31:02 +0200486 if (unmodified&&unmodified!="")
487 um=implode(old_explode(unmodified," ")[1..]," ");
488 if (um=="") um=0;
Zesstraf86ed742019-04-25 18:37:27 +0200489 if ( !(str=um || _unparsed_args()))
490 return 0;
491
Zesstrafb4cc3d2019-05-06 21:16:30 +0200492 int familymode;
Zesstraf332ded2019-04-25 18:40:02 +0200493 while(sizeof(str) >= 2 && str[0] == '-')
494 {
495 if (str[1] == 'f')
496 familymode = 1;
497 else
498 break;
499 // "-f " abschneiden
500 str = trim(str[2..], TRIM_LEFT);
501 }
502
MG Mud User88f12472016-06-24 23:31:02 +0200503 if (str == "*.*" || str == "*") {
504 write(break_string(
505 "Versuchs mal mit 'unalias .*', wenn Du wirklich alle Alias entfernen "
506 "willst.",78));
507 return 1;
508 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200509
510 mapping selected_aliases;
511 if (familymode)
512 selected_aliases=FALIASDB->QueryFamilyAlias();
513 else
514 selected_aliases = aliases;
515
516 string *to_delete;
517 // Genau ein Alias gegeben?
518 if (member(selected_aliases,str))
519 to_delete = ({str});
520 else // sonst als RegExp interpretieren
521 to_delete=regexp(m_indices(selected_aliases),("^"+str+"$"));
522
523 if (sizeof(to_delete))
Zesstraf86ed742019-04-25 18:37:27 +0200524 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200525 foreach(string key : to_delete)
Zesstraf86ed742019-04-25 18:37:27 +0200526 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200527 if (familymode)
528 FALIASDB->DeleteFamilyAlias(key);
529 else
530 m_delete(aliases, key);
531 // auf jeden Fall noch deaktivieren
532 m_delete(active_aliases, key);
MG Mud User88f12472016-06-24 23:31:02 +0200533 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200534 if (sizeof(to_delete) == 1)
535 write("Du entfernst das Alias \""+ to_delete[0] +"\".\n");
536 else
537 write(break_string(("Du entfernst folgende Aliase: "
538 +CountUp(to_delete) + ".\n"),75));
MG Mud User88f12472016-06-24 23:31:02 +0200539 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200540 else
541 write("So ein Alias hast Du nicht definiert.\n");
542
MG Mud User88f12472016-06-24 23:31:02 +0200543 return 1;
544}
545
546varargs string _unparsed_args(int level)
547{
548 return unparsed_args[level];
549}
550
551#define ARTIKEL ({"das","der","die","des","dem","den","ein","eine","einer",\
552 "eines"})
553
554#define TRENNER ({"in","aus","ueber","auf","unter","mit","durch","fuer",\
555 "von","vom","im","aufs","ein","weg","zurueck"})
556
557static string _single_spaces(string str)
558{
559 return regreplace(str, " *", " ", 1);
560}
561
562static mixed _return_args(string str)
563{
564 string *t,*t2,verb,s2;
565 int i,l,j,l2;
566
567 t=explode(trim(str,TRIM_BOTH)," ");
568 verb=t[0];
569 t = t[1..];
570 if (!sizeof(t))
571 {
572 unparsed_args[0]=unparsed_args[1]=unparsed_args[2]=0;
573 return str=verb;
574 }
575 else
576 str = unparsed_args[0] = implode(t, " ");
577
578 str=unparsed_args[1]=lower_case(_single_spaces(str));
579 t=regexplode(str,"\\<im\\>|\\<ins\\>");
580 for (i=1;i<sizeof(t);i+=2) t[i]="in";
581 t=regexplode(implode(t,""),"[\\,\\!\\:][\\,\\!\\:]*");
582 l=sizeof(t);
583 for(i=1;i<l;i+=2) t[i]="";
584 t=old_explode(implode(t,"")," ")-({""});
585 for (i=sizeof(t)-2;i>=0;i--)
586 {
587 if (member(ARTIKEL,t[i])>=0)
588 t=t[0..i-1]+t[i+1..];
589 }
590 unparsed_args[2]=implode(t," ");
591 t=regexplode((str=implode(t," ")),"[0-9][0-9]*\\.");
592 if ((l=sizeof(t))>2)
593 {
594 i=1;
595 while (i<l-1)
596 {
597 t[i]=" "+t[i][0..<2]+" ";
598 if ((l2=sizeof(t2=old_explode(t[i+1]," ")))<2)
599 t[i+1]+=t[i];
600 else
601 {
602 for (j=1;j<l2;j++)
603 {
604 if (member(TRENNER,t2[j])>=0)
605 {
606 t2[j-1]+=t[i];
607 l2=0;
608 }
609 }
610 if (!l2)
611 t[i+1]=implode(t2," ");
612 else
613 t[i+1]+=t[i];
614 }
615 t[i]="";
616 i+=2;
617 }
618 str=_single_spaces(verb+" "+implode(t," "));
619 if (str[<1]==' ') str=str[0..<2];
620 } else str=verb+(str==""?"":" "+str);
621 if (show_processing>2)
622 printf("-> {%s}\n",str);
623 return str;
624}
625
626static void decay_average()
627{
628 if (absolute_hb_count()-last_chg>14)
629 {
630 last_chg=absolute_hb_count()-last_chg;
631 if (last_chg>3000)
632 last_chg=absolute_hb_count(),cmds_per_time=0;
633 else
634 {
635 while (last_chg>14)
636 cmds_per_time=cmds_per_time*9/10, last_chg-=15;
637 last_chg=absolute_hb_count()-last_chg;
638 }
639 }
640}
641
642private void DelayPreparedSpells() {
643 mixed ps;
644
645 if (pointerp(ps=QueryProp(P_PREPARED_SPELL))
646 && sizeof(ps)>=1 && intp(ps[0])) {
647 ps[0]++;
648 SetProp(P_PREPARED_SPELL,ps);
649 write("Die Ausfuehrung Deines vorbereiteten Spruches wird verzoegert.\n");
650 } else if (ps) {
651 SetProp(P_PREPARED_SPELL,0);
652 }
653}
654
655static mixed bb;
656#ifndef BBMASTER
657#define BBMASTER "/secure/bbmaster"
658#endif
659
660/** Interpretiert Aliase und History-Kommandos
661 Eigentlich muesste hier noch die Umwandlung der Sonderzeichen
662 verschiedener Zeichensaetze mit convert_charset gemacht werden,
663 aber noch gibt es keine Moeglichkeit, den vom Spieler genutzten
664 Zeichensatz zu identifizieren.
665 \param[in] str string - Kommando des Spielers
666 \return interpretiertes Alias bzw. korrektes Kommando aus der History
667*/
668private string parsecommand(string str)
669{
670 if (str[0]=='\\')
671 {
672 // Kommando soll nicht interpretiert werden
673 return str[1..];
674 }
675 else if (str[0]=='&')
676 {
677 // Kommando aus der History
678 string cmd = str[1..];
679 int cmd_size = sizeof(cmd);
680 int cmd_found = 0;
681 if (cmd_size)
682 {
683 // Test ob &<text> etwas findet
684 for (int i=0;i<hist_size-1 && !cmd_found;i++)
685 {
686 int idx = (hist_size-i+hist_now-1)%hist_size;
687 if (history[idx][0..cmd_size-1]==cmd)
688 {
689 str = history[idx];
690 cmd_found = 1;
691 }
692 if (cmd_found)
693 {
694 if (show_processing)
695 printf("[%s]\n",str);
696 }
697 }
698 }
699 if (!cmd_found)
700 {
701 // Test, ob &<nr> klappt
702 int nummer;
703 if (str=="&&")
704 str = "&-0";
705 if (sscanf(str,"&%d",nummer))
706 {
707 if (nummer<0 || (!nummer && str[1]=='-'))
708 {
709 if (nummer<-(hist_size-1))
710 nummer=-1;
711 else
712 nummer=(hist_now+nummer-1+hist_size)%hist_size;
713 }
714 else
715 {
716 if (nummer>hist_now || hist_now-nummer>hist_size)
717 nummer=-1;
718 else
719 nummer=nummer%hist_size;
720 }
721 if (nummer<0
722 || ( (cmd=history[nummer]) =="\n\n") )
723 notify_fail("Der Befehl ist nicht in der History!\n");
724 else
725 {
726 str = cmd;
727 if (show_processing)
728 printf("[%s]\n",str);
729 }
730 }
731 }
732 }
733 switch (str)
734 {
735 case "n": return "norden";
736 case "s": return "sueden";
737 case "w": return "westen";
738 case "o": return "osten";
739 case "nw": return "nordwesten";
740 case "sw": return "suedwesten";
741 case "so": return "suedosten";
742 case "no": return "nordosten";
743 case "ob": return "oben";
744 case "u": return "unten";
745 }
746 // Test auf Alias
747 string output = "";
748 string* input = explode(str," ");
749 int input_size = sizeof(input);
Zesstrafb4cc3d2019-05-06 21:16:30 +0200750 mixed alias = active_aliases[input[0]];
MG Mud User88f12472016-06-24 23:31:02 +0200751 if (!alias)
752 return str;
Zesstrafb4cc3d2019-05-06 21:16:30 +0200753 // Das Alias ist in ein Array von Strings gespeichert. Alle
754 // Alias-Argument ($n, $* oder $n*) stehen an der jeweiligen Stelle als
755 // laufender Index im Array. An der Stelle werden die Argumente vom Alias
756 // eingefuegt, alle anderen Elemente werden in den output kopiert. Negative
757 // Zahlen stehen fuer $n*, d.h. alle Argument nach dem genannten.
758 // Bsp: ({"stecke ", 1, " in ", -2 })
MG Mud User88f12472016-06-24 23:31:02 +0200759 foreach (mixed a:alias)
760 {
761 if (!intp(a))
762 output += a;
763 else
764 {
765 if (a >= 0)
766 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200767 // Einzelnes Argument ($n). Argument anstelle von a einfuegen, falls
768 // genug angegeben wurden
MG Mud User88f12472016-06-24 23:31:02 +0200769 if (input_size > a)
770 output += input[a];
771 }
772 else
773 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200774 // Argumente ab n ($n*). Alle von a bis Ende einfuegen.
MG Mud User88f12472016-06-24 23:31:02 +0200775 a = -a;
776 if (input_size > a)
777 output += implode(input[a..]," ");
778 }
779 }
780 }
781 output = _single_spaces(output);
782 str = trim(output,TRIM_RIGHT);
783 if (show_processing>1)
784 printf("[%s]\n",str);
785 return str;
786}
787
788/** Behandelt alle Sonderfaelle der Eingabe des Spielers
789 Alle Befehle des Spielers, die nicht durch Objekte behandelt
790 werden sollen, werden hier erkannt und ausgefuehrt.
791 Dazu gehoert auch die Interpretation von Aliases und History-
792 befehlen.
793 \param[in] str string: Kommando des Spielers
794 \return auszufuehrendes Kommando
795 oder 0 fuer ein nicht interpretierbares Kommando
796 oder 1 fuer ein bereits durchgefuehrtes Kommando
797*/
798mixed modify_command(string str)
799{
800
801 if (extern_call() && previous_object() &&
802 (previous_object()!=this_object() || process_call()) )
803 {
804 return 0;
805 }
806
807 // Leerzeichen an den Enden abschneiden.
808 str = trim(str, TRIM_BOTH);
809
810 if (bb)
811 BBMASTER->BBWrite(trim(str,TRIM_RIGHT,"\n"), 0);
812
813 decay_average();
814 cmds_per_time+=10000;
815
816 unparsed_args[0]=unparsed_args[1]=unparsed_args[2]=unmodified="";
817
818 if (!sizeof(str)) return "";
819
820 // Kommando wird geparst
821 unmodified=parsecommand(str);
822
823 // Environment schonmal merken.
824 last_command_env=environment();
825
826 if (unmodified == "")
827 return "";
828 // Kommando in History merken, auch wenn es im Kommandoblock abgebrochen
829 // wird.
830 AddHistory(unmodified);
831
832 // pruefen, ob Kommandoblock gesetzt ist.
833 // (Fuer Magier mit mschau ein wird das ignoriert.)
834 // BTW: Es wird absichtlich nicht das Ergebnis der Closure zurueckgegeben,
835 // sonst wuerde man beliebigen Objekten nicht nur das Abbrechen, sondern
836 // auch das Aendern von Kommandos ermoeglichen.
837 if (disablecommands && !IS_LEARNING(ME) )
838 {
839 if (disablecommands[B_TIME] >= time()
840 && objectp(disablecommands[B_OBJECT]))
841 {
842 // disablecommands valid
843 // hart-kodierte Ausnameliste pruefen
844 if ( member(({"mrufe","mschau","bug","idee","typo","detail"}),
845 explode(str," ")[0]) == -1)
846 {
847 if (closurep(disablecommands[B_VALUE]))
848 {
849 if (funcall(disablecommands[B_VALUE],_return_args(unmodified)))
850 {
851 // Non-zero Closure-Ergebnis, Abbruch. Die gerufene Funktion ist
852 // fuer eine geeignete Meldung an den Spieler verantwortlich.
853 return 1;
854 }
855 }
856 // wenn Text, dann auch pruefen, ob das Kommandoverb in den Ausnahmen
857 // steht. (query_verb() geht leider hier noch nicht.)
858 else if (stringp(disablecommands[B_VALUE])
859 && member(disablecommands[B_EXCEPTIONS],
860 explode(str," ")[0]) == -1)
861 {
862 // meldung ausgeben...
863 tell_object(PL, disablecommands[B_VALUE]);
864 // und Ende...
865 return 1;
866 }
867 }
868 }
869 else disablecommands=0;
870 }
871
872 // Verfolger direkt ins Env reinholen.
873 if (remove_call_out("TakeFollowers")>=0)
874 catch(TakeFollowers();publish);
875
876 DelayPreparedSpells();
877
878 // Historyeintrag korrigieren
879 if (unmodified[0]=='^')
880 {
881 string *oldnew,pre,post;
882 if (sizeof(oldnew=explode(unmodified,"^"))>2)
883 {
884 int hist_idx = (hist_now-1)%hist_size;
885 sscanf(history[hist_idx],"%s"+oldnew[1]+"%s", pre, post);
886 unmodified = pre+oldnew[2]+post;
887 if (show_processing)
888 write("["+unmodified+"]\n");
889 // korrigiertes Kommando natuerlich auch in die History.
890 AddHistory(unmodified);
891 }
892 }
893
894 if( bb )
895 BBMASTER->BBWrite(" -> " + unmodified, 1);
896
897 if (show_processing>1)
898 printf("[%s]\n",unmodified);
899
900 mixed ret = _return_args(unmodified);
901
902 // wenn Spieler eingewilligt hat und die SyntaxDB geladen ist, Befehl
903 // dorthin melden.
904 if (syntaxdb)
905 {
906 if (!objectp(syntaxdb[0]))
907 syntaxdb[0] = find_object("/secure/syntaxdb");
908 if (syntaxdb[0])
909 catch(syntaxdb[0]->start_cmd(unmodified);nolog);
910 }
911 return ret;
912}
913
914static int do_list(string str)
915{
916 string *cmdlist;
917 int i;
918
919 if (!QueryProp(P_WANTS_TO_LEARN))
920 return 0;
921 cmdlist=old_explode(_unparsed_args()||"",";")-({ "" });
922 for (i=0;i<sizeof(cmdlist);i++)
923 {
924 cmdlist[i]=implode(old_explode(cmdlist[i]," ")-({}), " ");
925 if (show_processing)
926 write("["+cmdlist[i]+"]\n");
927 command(cmdlist[i]);
928 }
929 return 1;
930}
931
932//falls die aliasliste kaputt ist ...
933
934int unalias_all()
935{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200936 if (IS_ELDER(this_interactive()))
937 {
938 aliases=([]);
939 merge_family_aliases();
940 }
MG Mud User88f12472016-06-24 23:31:02 +0200941 return 1;
942}
943
944object _query_last_command_env()
945{
946 return last_command_env;
947}
948
949int _query_show_alias_processing()
950{
951 return show_processing;
952}
953
954int _query_histmin()
955{
956 return histmin;
957}
958
959varargs void AddAction(mixed fun, mixed cmd, int flag, int lvl)
960{
961 int i;
962 mixed *cmds;
963
964 log_file( "ARCH/ADD_ACTION", sprintf(
965 "%s:\n TO: %O TP: %O PO: %O\n fun: %O cmd: %O flag: %O lvl: %O",
966 dtime(time()), this_object(), this_player(), previous_object(),
967 fun, cmd, flag, lvl));
968
969 if (!(cmds=Query(P_LOCALCMDS))) cmds=({});
970
971 if (!pointerp(cmd)) cmd=({cmd});
972
973 for (i = sizeof(cmd)-1; i>=0; i--)
974 cmds += ({({ cmd[i] , fun, flag, lvl})});
975
976 Set(P_LOCALCMDS, cmds);
977}
978
979static int auswerten(mixed cmd, string str)
980{
981 if (closurep(cmd))
982 return funcall(cmd,str);
983 if (stringp(cmd))
984 return call_other(this_object(),cmd,str);
985 return 0;
986}
987
988static varargs int __auswerten(string str, string intern)
989{
990 string verb;
991 mixed *cmd, cmds;
992 int i,ret,lvl,l,vl;
993
994 if (!intern)
995 verb=query_verb();
996 else
997 verb=intern;
998 lvl=query_wiz_level(ME);
999 vl=sizeof(verb);
1000 cmds=QueryProp(P_LOCALCMDS);
1001
1002 for(i=sizeof(cmds)-1;i>=0;i--)
1003 {
1004 cmd=cmds[i],l=sizeof(cmd[0]);
1005 if (cmd[0]==verb[0..l-1] && cmd[3]<=lvl && (cmd[2]||vl==l) &&
1006 (ret=auswerten(cmd[1],str)))
1007 return ret;
1008 }
1009 // An dieser Stelle gibt es hier und vermutlich nirgendwo anders etwas, was
1010 // dieses Kommando als gueltig betrachtet. Wir informieren ggf. die
1011 // Syntax-DB. (Achtung: wenn jemand ne add_action() im Spielerobjekt
1012 // einbaut, die vor dieser eingetragen wird, ist die Annahme ggf. falsch.)
1013 // wenn Spieler eingewilligt hat und die SyntaxDB geladen ist, Befehl
1014 // dorthin melden.
1015 if (syntaxdb)
1016 {
1017 if (!objectp(syntaxdb[0]))
1018 syntaxdb[0] = find_object("/secure/syntaxdb");
1019 if (syntaxdb[0])
1020 catch(syntaxdb[0]->cmd_unsuccessful();nolog);
1021 }
1022
1023 return 0;
1024}
1025
1026public void syntax_log_ep(int type)
1027{
1028 // wenn Spieler eingewilligt hat und die SyntaxDB geladen ist, Befehl
1029 // dorthin melden.
1030 if (syntaxdb && syntaxdb[0])
1031 {
1032 catch(syntaxdb[0]->LogEP(type);nolog);
1033 }
1034}
1035
1036static mixed _query_localcmds()
1037{
1038 mixed *l;
1039
1040 l=Query(P_LOCALCMDS);
1041 if (!pointerp(l))
1042 l=({});
1043 return ({
1044 ({"ali","alias",0,0}),
1045 ({"alias","alias",0,0}),
1046 ({"unali","unalias",1,0}),
1047 ({"histmin","histmin",0,0}),
1048 ({"histlen","histlen",0,0}),
1049 ({"hist","show_hist",0,0}),
1050 ({"history","show_hist",0,0}),
1051 ({"do","do_list",0,LEARNER_LVL}),
1052 ({"ersetzungsanzeige","replacedisplay",0,0}),
1053 ({"syntaxsammlung","collect_cmds",0,0}),
1054 ({"fehlermeldung","set_errormessage",0,SEER_LVL}),
1055 })+l;
1056}
1057
1058static int collect_cmds(string cmd)
1059{
1060 if (!stringp(cmd))
1061 {
1062 _notify("Mit diesem Befehl kannst Du mithelfen, Syntaxen im MG zu "
1063 "verbessern. Wenn Du einverstanden bist, speichern wir "
1064 "anonym (d.h. ohne Deinen Charnamen), welche Deiner Befehle "
1065 "erfolgreich und nicht erfolgreich waren. Uebliche "
1066 "Kommunikationsbefehle werden dabei nicht gespeichert.",
1067 0);
1068 _notify("Mit 'syntaxsammlung ja' kannst Du die Speicherung einschalten, "
1069 "mit 'syntaxsammlung nein' kannst Du sie ausschalten.",0);
1070 _notify("Deine Befehle werden zur Zeit"
1071 + (QueryProp("_syntaxdb") ? " " : " NICHT ")
1072 + "gespeichert.", 0);
1073 }
1074 else if (cmd == "ja")
1075 {
1076 SetProp("_syntaxdb", 1);
1077 _notify("Ab jetzt werden Deine Befehle gespeichert. Vielen Dank!", 0);
1078 }
1079 else
1080 {
1081 SetProp("_syntaxdb", 0);
1082 _notify("Ab jetzt werden Deine Befehle NICHT gespeichert.", 0);
1083 }
1084 return 1;
1085}
1086
1087int _query_command_average()
1088{
1089 decay_average();
1090 return cmds_per_time;
1091}
1092
1093nomask void __set_bb(int flag) {
1094 if( previous_object()!=find_object(BBMASTER) || process_call() )
1095 return;
1096 bb=flag;
1097}
1098
1099
1100nomask public void countCmds( int type, string key )
1101{
1102 string tmp;
1103
1104 if ( this_player() != this_interactive()
1105 || this_interactive() != this_object()
1106 || member( cmd_types, type ) < 0 )
1107 return;
1108
1109 tmp = sprintf( "%d\n%s", type, key );
1110
1111 commands -= ({ tmp });
1112 commands += ({ tmp });
1113 commands = commands[0..max_commands-1];
1114}
1115
1116
1117nomask public string *getCmds()
1118{
1119 string *tmp;
1120
1121 if ( previous_object() != find_object(BBMASTER) )
1122 return ({});
1123
1124 tmp = commands;
1125 commands = ({});
1126
1127 return tmp;
1128}
1129
1130/*
1131 * Force the monster to do a command. The force_us() function isn't
1132 * always good, because it checks the level of the caller, and this function
1133 * can be called by a room.
1134 */
1135int command_me(string cmd)
1136{
1137 if (IS_LEARNER(ME))
1138 {
1139 if (!this_interactive() || !previous_object())
1140 return 0;
1141 if( geteuid(ME)!=geteuid(this_interactive())
1142 || geteuid(ME)!=geteuid(previous_object()) )
1143 {
1144 if( query_wiz_level(ME)<query_wiz_level(previous_object()))
1145 tell_object(ME,previous_object()->name()+" zwingt Dich zu: "
1146 + cmd + ".\n");
1147 else
1148 {
1149 tell_object(ME,previous_object()->name()
1150 + " versucht, Dich zu " + cmd + " zu zwingen.\n" );
1151 return 0;
1152 }
1153 }
1154 }
1155 return command(cmd);
1156}
1157
1158
1159static mixed _query_p_lib_disablecommands() {
1160 // abgelaufen oder Objekt zerstoert? Weg damit.
1161 if (pointerp(disablecommands)
1162 && (disablecommands[B_TIME] < time()
1163 || !objectp(disablecommands[B_OBJECT])) )
1164 return(disablecommands = 0);
1165
1166 // sonst Kopie zurueck (copy(0) geht)
1167 return(copy(disablecommands));
1168}
1169
1170static mixed _set_p_lib_disablecommands(mixed data) {
1171
1172 // setzendes Objekt ermitteln, da diese Funktion nur per SetProp() gerufen
1173 // werden sollte (!), ist das PO(1);
1174 object origin = previous_object(1);
1175 // wenn nicht existent, direkt abbruch
1176 if (!objectp(origin))
1177 return _query_p_lib_disablecommands();
1178
1179 // Prop loeschen? Explizit loeschen darf jeder, allerdings nicht direkt
1180 // ungeprueft ueberschreiben.
1181 if (!data) {
1182 return (disablecommands = 0 );
1183 }
1184 // mal direkt buggen bei falschen Datentyp, damits auffaellt.
1185 if (!pointerp(data) || sizeof(data) < 2 || !intp(data[0])
1186 || (!stringp(data[1]) && !closurep(data[1]))
1187 || (sizeof(data) >= 3 && !pointerp(data[2])) )
1188 raise_error(sprintf(
1189 "Wrong data type for P_DISABLE_COMMANDS. Expected Array with "
1190 "2 or 3 elements (int, string|closure, [string*]), got %.25O\n",
1191 data));
1192
1193 // Wenn abgelaufen oder gleiches Objekt wie letztes Mal: eintragen.
1194 if (!disablecommands || (disablecommands[B_TIME] < time()
1195 || !objectp(disablecommands[B_OBJECT])
1196 || disablecommands[B_OBJECT] == origin) ) {
1197 // Loggen nur, wenn eine Closure eingetragen wird. Reduziert den
1198 // Logscroll und Strings haben deutlich weniger Missbrauchspotential.
1199 if (closurep(data[1])) {
1200 CBLOG(sprintf("[%s] CB gesetzt von %O, gueltig bis %s, Daten: %O\n",
1201 strftime("%Y%m%d-%H:%M:%S"),origin,
1202 strftime("%Y%m%d-%H:%M:%S",data[0]),
1203 (stringp(data[1]) ? regreplace(data[1],"\n","\\n",0)
1204 : data[1])));
1205 }
1206 if (sizeof(data)+1 <= B_EXCEPTIONS)
1207 disablecommands = ({ origin, data[0], data[1], ({}) });
1208 else
1209 disablecommands = ({ origin, data[0], data[1], data[2] });
1210 return(copy(disablecommands));
1211 }
1212
1213 return(_query_p_lib_disablecommands());
1214}
1215
1216static mixed _set__syntaxdb(mixed v)
1217{
1218 Set("_syntaxdb", v, F_VALUE);
1219 if (v)
1220 syntaxdb = ({find_object("/secure/syntaxdb")});
1221 else
1222 syntaxdb = 0;
1223 return QueryProp("_syntaxdb");
1224}
1225