blob: 727f34f885f5ec97838b394f60ad46c9d329cbf4 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001/*
2 * MGtool-1.3
3 * File: MGtool.c
4 * Maintainer: Kirk@MorgenGrauen
5 */
6
7/*------------------------------------------*/
8/* the original Xtool is copyrighted by Hyp */
9/*------------------------------------------*/
10
11#pragma strict_types
12
13inherit "/std/thing/properties";
14
15#include <properties.h>
16#if !defined(QUERYCACHED)
17#define QUERYCACHED 4096
18#endif
19#if !defined (SETCACHED)
20#define SETCACHED 4096
21#endif
22#include <moving.h>
23#include "/secure/wizlevels.h"
24#include "/secure/config.h"
25#include <userinfo.h>
26#include <defines.h>
27
28#include "MGtool/tool.h"
29
30#include "MGtool/toollib.h"
31
32#define XDBG 1
33
34nosave object cloner;
35nosave object msgto=NULL;
36nosave string *manpath=({TOOL_PATH+"/man.d/",
37 "/doc/efun/",
38 "/doc/lfun/",
39 "/doc/w/",
40 "/doc/helpdir/",
41 "/doc/LPC/",
42 "/doc/std/",
43 "/doc/concepts/",
44 ""});
45nosave string morefile=NULL;
46nosave string *scriptline=NULL;
47nosave string *history=allocate(MAX_HISTORY);
48nosave int moreflag=FALSE;
49nosave int moreoffset=1;
50nosave int term=NULL;
51nosave int scriptsize=NULL;
52nosave int nostore=FALSE;
53nosave int xlight=0;
54nosave int pipe_in=FALSE;
55nosave int pipe_out=FALSE;
56nosave int pipe_ovr=TRUE;
57nosave string pipe_if=NULL;
58nosave string pipe_of=NULL;
59nosave int xtk=FALSE;
60nosave mapping variable=([]);
61nosave string *cmds;
62private nosave mapping line_buffer=([]);
63private nosave string line_buffer_name="";
64private nosave string more_searchexpr="";
65int morelines=MORE_LINES;
66int modi=(MODE_FIRST|MODE_PROTECT|MODE_SHORT);
67
68#include "MGtool/toollib.c"
69#include "MGtool/toolcmd.c"
70
71#define SafeReturn(x) \
72{ \
73 cmds=({}); \
74 pipe_in=FALSE; \
75 pipe_of=NULL; \
76 pipe_ovr=TRUE; \
77 pipe_out=FALSE; \
78 pipe_of=NULL; \
79 return (x); \
80}
81
82/*----------------------------------------------------------------------
83 * check some security aspects
84 */
85
86static int security()
87{
88 object prev;
89
90 if( process_call() || getuid()!=getuid(cloner) ) return FALSE; // Rumata
91
92 TK("UID: "+getuid(ME)+" cloner:"+getuid(cloner));
93// TK("prev: "+object_name(PREV)+" me:"+object_name(ME));
94 if(prev=PREV)
95 {
96 if(!cloner)
97 return TRUE;
98 if(getuid(prev)==ROOTID||IS_ARCH(prev))
99 return TRUE;
100 if(prev==ME)
101 return TRUE;
102 return secure_level()>=query_wiz_level(cloner); // Rumata
103 //return getuid(prev)==getuid()&&geteuid(prev)==geteuid()&&cloner==RTP;
104 }
105 else
106 return cloner==NULL;
107}
108
109/*----------------------------------------------------------------------
110 * own write function
111 */
112
113static int Write(string str)
114{
115 if(!stringp(str) || str=="")
116 return FALSE;
117 if(!cloner && objectp(this_player()))
118 write(str);
119 else
120 tell_object(cloner, str);
121 return TRUE;
122}
123
124/*----------------------------------------------------------------------
125 * own command function
126 */
127
128static int Command(string str)
129{
130 int i;
131 TK("Command: str: "+(str?str:"(NULL)"));
132 nostore++;
133 if(MODE(MODE_ECHO))
134 WLN("Doing: "+str);
135 i=(int)cloner->command_me(str);
136 nostore--;
137 return i;
138}
139
140/*----------------------------------------------------------------------
141 * object searching
142 */
143
144static varargs object XFindObj(string str, int silent)
145{
146 object obj, env;
147 string *strs;
148 int i, s, cnt;
149
150 if(!str)
151 return NULL;
152 TK("XFindObj: str: "+(str?str:"(NULL)"));
153 env=ENV(cloner);
154 str=string_replace(str, "\\.","°01");
155 str=string_replace(str, "\\^", "°02");
156 str=string_replace(str, "\\$", "°03");
157 str=string_replace(str, "\\\\", "\\");
158 if (find_object(str)) return find_object(str);
159 if (file_size(str)>1) {
160 call_other(str, "???");
161 return find_object(str);
162 }
163 s=sizeof(strs=strip_explode(str, "."));
164 while(s--)
165 {
166 if(strs[i]=="m"||strs[i]=="me")
167 strs[i]=RNAME(cloner);
168 else if(strs[i]=="h"||strs[i]=="here")
169 strs[i]=object_name(ENV(cloner));
170 if(obj=FindObj(strs[i++],env,(silent?1:0)))
171 env=obj;
172 else
173 break;
174 }
175 return obj;
176}
177
178static varargs object FindObj(string str, object env, int silent)
179{
180 object obj, *inv;
181 string tmp;
182 int num, e;
183
184 if (!stringp(str) || !sizeof(str) || !objectp(env))
185 return NULL;
186 str=string_replace(str, "°01", ".");
187 while(str[e++]=='^')
188 ;
189 str=str[--e..<1];
190 str=string_replace(str, "°02", "^");
191 if(obj=VarToObj(str))
192 ;
193 else if(str[0]=='')
194 str=string_replace(str, "°03", "$");
195 else if(sscanf(str, "%d", num)&&(inv=all_inventory(env)))
196 {
197 if(num>0&&num<=sizeof(inv))
198 obj=inv[num-1];
199 else
200 {
201 WDLN("Specified object number out of range [1-"+sizeof(inv)+"]");
202 return NULL;
203 }
204 }
205 if(obj||(obj=present(str, env))||
206 (obj=find_player(LOWER(str)))||
207 (obj=find_living(str))||
208 (obj=find_object(long_path(str))))
209 {
210 while(e--)
211 {
212 if(!(obj=ENV(obj)))
213 {
214 W("Specified object has no environment [");
215 while(e--)
216 W("^");
217 WDLN(str+"]");
218 return NULL;
219 }
220 }
221 }
222 else
223 if(!silent)
224 WDLN("Specified object does not exist ["+str+"]");
225 return obj;
226}
227
228/*----------------------------------------------------------------------
229 * object variable handling
230 */
231
232static object VarToObj(string str)
233{
234 if (!stringp(str) || !sizeof(str) || str[0]!='$')
235 return NULL;
236 switch(str)
237 {
238 case "$m":
239 case "$me":
240 return cloner;
241 case "$h":
242 case "$here":
243 return ENV(cloner);
244 default:
245 return variable[str[1..<1]];
246 }
247 return(NULL); //never reached
248}
249
250static string VarToFile(string str)
251{
252 return source_file_name(VarToObj(str));
253}
254
255static string VarToPureFile(string str)
256{
257 return pure_file_name(VarToObj(str));
258}
259
260/*----------------------------------------------------------------------
261 * object description printing
262 */
263
264static void PrintObj(object obj, string file)
265{
266 object item, tmp;
267 string str;
268 int i;
269
270 SECURE1();
271 if(!obj)
272 return;
273 PrintShort("Short: ", obj, file);
274 if(!file||file=="")
275 WLN("Long :");
276 else
277 write_file(file,"Long :\n");
278 if(query_once_interactive(obj))
279 str=capitalize(getuid(obj));
280 else
281 {
282 if(object_name(obj)[0..26]=="/d/unterwelt/objekte/teddy#" &&
283 IS_ARCH(this_interactive()))
284 str="Ein Teddy (stumm)";
285 else
286 {
287 if(str=(string)obj->QueryProp(P_INT_LONG))
288 ;
289 else if(str=(string)obj->QueryProp(P_LONG))
290 ;
291 else
292 str="- no long description -\n";
293 }
294 }
295 if(!file||file=="")
296 W(str);
297 else
298 write_file(file,str);
299 FORALL(item, obj)
300 {
301 if(!i)
302 if(!file||file=="")
303 WLN("Content:");
304 else
305 write_file(file,"Content:\n");
306 PrintShort(ARIGHT(++i+". ", 4, " "), item, file);
307 }
308}
309
310static string ObjFile(object obj)
311{
312 return "["+short_path(object_name(obj))+"]";
313}
314
315static varargs void PrintShort(string pre, object obj, string file)
316{
317 string str;
318
319 SECURE1();
320 if(!obj)
321 return;
322 if(MODE(MODE_SHORT))
323 {
324 if (query_once_interactive(obj))
325 str=capitalize(getuid(obj));
326 else
327 {
328 if(!((str=(string)obj->QueryProp(P_INT_SHORT))||
329 (str=(string)obj->QueryProp(P_SHORT))))
330 if(is_player(obj))
331 str=CRNAME(obj)+" (invisible)";
332 else
333 str="- no short description -";
334 }
335 str=ALEFT(sprintf("%O ",str), 34, ".")+" ";
336 }
337 else
338 str="";
339 if(interactive(obj))
340 str+="i";
341 else if(living(obj))
342 str+="l";
343 else
344 str+=".";
345 str+=(shadow(obj, 0) ? "s" : ".");
346 if(!file||file=="")
347 WLN((pre+CAP(str)+" "+ObjFile(obj))[0..79]);
348 else
349 write_file(file,(pre+CAP(str)+" "+ObjFile(obj))[0..79]+"\n");
350}
351
352static varargs void DeepPrintShort(object env, int indent, string pre, string file)
353{
354 int i;
355 object item;
356 string str;
357
358 SECURE1();
359 if(!env)
360 return;
361 for(i=indent,str=""; i--; str+=" ");
362 if(pre)
363 str+=pre;
364 if(!file||file=="")
365 W(str);
366 else
367 write_file(file,str);
368 i++;
369 PrintShort("",env,file);
370 FORALL(item, env)
371 DeepPrintShort(item,indent+1,ARIGHT((++i)+". ",4," "),file);
372}
373
374static string break_string_hard(string str, int len, string pre)
375{
376 int s,p,t;
377 string tmp;
378
379 if(!str||!(s=sizeof(str)))
380 return "";
381 t=len-(p=sizeof(pre))-1;
382
383 tmp="";
384 while(p+s>len)
385 {
386 tmp+=pre+str[0..t]+"\n";
387 str=str[t+1..];
388 s-=t;
389 }
390 if(sizeof(str))
391 tmp+=pre+str[0..]+"\n";
392 return tmp;
393}
394
395static void dprop(string key, mixed data, object obj)
396{
397 if(pipe_out&&pipe_of)
398 write_file(pipe_of,break_string_hard(mixed_to_string(obj->QueryProp(key),MAX_RECURSION),78,ALEFT(key+" ",18,".")+" = "));
399 else
400 W(break_string_hard(mixed_to_string(obj->QueryProp(key),MAX_RECURSION),78,ALEFT(key+" ",18,".")+" = "));
401}
402
403static string propflags(string key, object ob)
404{
405 int tmp;
406 string *flags;
407 tmp=(int)ob->Query(key,1);
408 flags=({});
409 tmp&SAVE ? flags+=({"SAV"}) : flags+=({" "});
410 tmp&PROTECTED ? flags+=({"PRO"}) : flags+=({" "});
411 tmp&SECURED ? flags+=({"SEC"}) : flags+=({" "});
412 tmp&NOSETMETHOD ? flags+=({"NSM"}) : flags+=({" "});
413 tmp&SETMNOTFOUND ? flags+=({"SMN"}) : flags+=({" "});
414 tmp&QUERYMNOTFOUND ? flags+=({"QMN"}) : flags+=({" "});
415 tmp&QUERYCACHED ? flags+=({"QCA"}) : flags+=({" "});
416 tmp&SETCACHED ? flags+=({"SCA"}) : flags+=({" "});
417 return ""+implode(flags,"|");
418}
419
420static void dprop2(string key, mixed data, object ob)
421{
422 if(pipe_out&&pipe_of)
423 write_file(pipe_of,break_string_hard(mixed_to_string(propflags(key,ob),MAX_RECURSION),78,ALEFT(key+" ",18,".")+" = "));
424 else
425 W(break_string_hard(mixed_to_string(propflags(key,ob),MAX_RECURSION),78,ALEFT(key+" ",18,".")+" = "));
426}
427
428static mixed propmethods(string key, object ob)
429{
430 return (mixed)ob->Query(key,2);
431}
432
433static void dprop3(string key, mixed data, object ob)
434{
435 if(pipe_out&&pipe_of)
436 write_file(pipe_of,break_string_hard(mixed_to_string(propmethods(key,ob),MAX_RECURSION),78,ALEFT(key+" ",18,".")+" = "));
437 else
438 W(break_string_hard(mixed_to_string(propmethods(key,ob),MAX_RECURSION),78,ALEFT(key+" ",18,".")+" = "));
439}
440
441static void DumpProperties(object obj, int flag)
442{
443 SECURE1();
444 if(!obj)
445 return;
446 PIPE_DELETE(pipe_of);
447 switch (flag) {
448 case 0:
449 walk_mapping(((mapping *)(obj->__query_properties()))[0],#'dprop,obj); //')
450 break;
451 case 1:
452 walk_mapping(((mapping *)(obj->__query_properties()))[0],#'dprop2,obj); //')
453 break;
454 case 2:
455 walk_mapping(((mapping *)(obj->__query_properties()))[0],#'dprop3,obj); //')
456 break;
457 }
458}
459
460/*----------------------------------------------------------------------
461 * moving objects
462 */
463
464static int MoveObj(object obj1, object obj2, int silent)
465{
466 int err;
467 object oldenv;
468
469 SECURE2(FALSE);
470 if(!(obj1&&obj2))
471 return FALSE;
472 oldenv=ENV(obj1);
473 err=(int)obj1->move(obj2, M_SILENT|M_NOCHECK);
474 if(!silent)
475 switch(err)
476 {
477 case ME_PLAYER:
478 WDLN("Object returned ME_PLAYER");
479 if(oldenv && oldenv != ENV(obj1))
480 WDLN("Object has been moved");
481 return FALSE;
482 case ME_TOO_HEAVY:
483 WDLN("Object returned ME_TOO_HEAVY");
484 if(oldenv && oldenv != ENV(obj1))
485 WDLN("Object has been moved");
486 return FALSE;
487 case ME_CANT_TPORT_IN:
488 WDLN("Object returned ME_CANT_TPORT_IN");
489 if(oldenv && oldenv != ENV(obj1))
490 WDLN("Object has been moved");
491 return FALSE;
492 case ME_CANT_TPORT_OUT:
493 WDLN("Object returned ME_CANT_TPORT_OUT");
494 if(oldenv && oldenv != ENV(obj1))
495 WDLN("Object has been moved");
496 return FALSE;
497 default:
498 WDLN("Object returned unknown return value");
499 return FALSE;
500 }
501 return TRUE;
502}
503
504/*----------------------------------------------------------------------
505 * save destructing of objects
506 */
507
508static void Destruct(object obj)
509{
510 if(!obj || !this_object())
511 return;
512 catch(obj->remove());
513 if(objectp(obj) && !query_once_interactive(obj))
514 destruct(obj);
515}
516
517static void DeepClean(object obj)
518{
519 if(!obj)
520 return;
521 filter(filter(deep_inventory(obj), "is_not_player", ME),
522 "Destruct", ME);
523 if(is_not_player(obj))
524 Destruct(obj);
525}
526
527/*----------------------------------------------------------------------
528 * Show the inheritance tree of objects
529 */
530
531static object *SubNodes(object obj)
532{
533 int s;
534 object *objs;
535 string *inlist;
536
537 if(!obj)
538 return NULL;
539 inlist=inherit_list(obj);
540 s=sizeof(inlist);
541 objs=({});
542 while(s-->1)
543 objs=({find_object(inlist[s])})+objs;
544 return objs;
545}
546
547static void Inheritance(object obj, string func, string pre)
548{
549 int i, s;
550 object *ln;
551 string str;
552
553 if(!obj)
554 return;
555 str=pre+" "+ObjFile(obj);
556 if(func)
557 {
558 str=ALEFT(str+" ", 50, ".");
559 if(function_exists(func, obj)==object_name(obj))
560 str+=ARIGHT(" "+func, 19, ".");
561 else
562 str+=ARIGHT("", 19, ".");
563 }
564 if(pipe_out&&pipe_of)
565 write_file(pipe_of,str+"\n");
566 else
567 WLN(str);
568 ln=SubNodes(obj);
569 for(i=0; i<sizeof(ln); i++)
570 ln=ln-SubNodes(ln[i]);
571 s=sizeof(ln);
572 for(i=0; i<s; i++)
573 Inheritance(ln[i], func, pre+".....");
574}
575
576/*----------------------------------------------------------------------
577 * file name handling
578 */
579
580static string XFile(string file)
581{
582 TK("XFile: file: "+(file?file:"(NULL)"));
583 if(file)
584 switch(file[0])
585 {
586 case '@':
587 return source_file_name(XFindObj(file[1..<1]));
588 case '$':
589 return source_file_name(XFindObj(file));
590 default:
591 return old_explode(long_path(file),"#")[0];
592 }
593 return NULL;
594}
595
596static string XFindFile(string file)
597{
598 TK("XFindFile: file: "+(file?file:"(NULL)"));
599 if(file=XFile(file))
600 {
601 if(file_size(file)>=0)
602 return file;
603 if(file[<3..<1]!=".c" && file_size(file+".c")>0)
604 return file+".c";
605 }
606 WDLN("File not found or not readable ["+short_path(file)+"]");
607 return NULL;
608}
609
610/*----------------------------------------------------------------------
611 * file printing, searching and executing
612 */
613
614static void XMoreFile(string file, int flag)
615{
616 int s,size;
617
618 SECURE1();
619 if(!file)
620 return;
621
622 // term=(string)cloner->QueryProp(P_TTY)!="dumb";
623 if((size=(file_size(morefile=long_path(file))))>0)
624 {
625 if(size>100000)
626 WDLN("Warning: large file");
627 MoreFile(NULL);
628 }
629 else if(flag)
630 WDLN("Cannot read file");
631}
632
633/*
634static string read_buffer(string filename, int start, int number)
635{
636 mixed tmp;
637 string result;
638 int current;
639
640 if(!filename||filename=="")
641 return "";
642 if(number<=1)
643 number=1;
644 number--;
645 result="";
646 if(filename!=line_buffer_name)
647 {
648 // TK("read_buffer: initializing");
649 line_buffer=([]);
650 line_buffer_name=filename;
651 current=0;
652 }
653 else
654 current=start;
655
656 while(current<=start+number && stringp((tmp=load_buffer(current++))))
657 if(current>=start)
658 result+=tmp;
659 return result;
660}
661
662static string load_buffer(int line)
663{
664 int i, current, start, length, *idx;
665
666 if(intp(line_buffer[line]))
667 {
668 // TK("load_buffer: Notfound: "+line);
669 current=line;
670 while(current>0&&intp(line_buffer[--current]));
671 for(i=current;i<=line;i++)
672 {
673 // TK("load_buffer: trying: "+i);
674 if(i>0)
675 idx=line_buffer[i-1];
676 else
677 idx=({0,0});
678 length=read_line((start=idx[0]+idx[1]));
679 // TK("load_buffer: "+start+"/"+length);
680 line_buffer[i]=({start,length});
681 }
682 }
683 idx=line_buffer[line];
684 return
685 read_bytes(line_buffer_name,idx[0],idx[1]);
686}
687
688static int read_line(int offset)
689{
690 mixed loc_buf;
691 int length, pos;
692
693 // TK("read_line: "+offset);
694 length=0;
695 while(!intp((loc_buf=read_bytes(line_buffer_name,offset+length,1024))))
696 {
697 if((pos=member(loc_buf,'\n'))>=0)
698 return length+pos+1;
699 length+=1024;
700 }
701 return length;
702}
703*/
704
705static void MoreFile(string str)
706{
707 int i, off;
708 string f, l, r;
709
710 SECURE1();
711
712 if (str /*&& sizeof(str)*/)
713 {
714 if( !sizeof(str) ) str="\0";
715 if(term)
716 W("M");
717 switch(str[0])
718 {
719 case 'q':
720 case 'x':
721 moreflag=FALSE;
722 moreoffset=1;
723 if(morefile==TMP_FILE||morefile==PIPE_FILE)
724 rm(morefile);
725 return NULL;
726 break;
727 case 'P':
728 case 'U':
729 moreflag=FALSE;
730 moreoffset=moreoffset-morelines;
731 case 'p':
732 case 'u':
733 moreoffset=moreoffset-2*morelines;
734 break;
735 case 'D':
736 case 'N':
737 moreoffset+=morelines;
738 case 0: /* RETURN */
739 case 'd':
740 if(moreflag)
741 {
742 moreflag=FALSE;
743 moreoffset=1;
744 if(morefile==TMP_FILE)
745 rm(morefile);
746 return;
747 }
748 break;
749 case '/':
750 moreoffset--;
751 more_searchexpr=str[1..<1];
752 case 'n':
753 i=moreoffset-morelines+1;
754 if(more_searchexpr=="")
755 {
756 WDLN("No previous regular expression");
757 return;
758 }
759 if(!regexp(({"dummy"}), more_searchexpr))
760 WDLN("Bad regular expression");
761 else
762 while((l=read_file(morefile, i++, 1))&&
763 !sizeof(regexp(({l}), more_searchexpr)))
764 ;
765 if(l)
766 {
767 WLN("*** Skipping ...");
768 moreoffset=i-1;
769 }
770 else
771 {
772 WLN("*** Pattern not found");
773 moreoffset-=morelines;
774 }
775 break;
776 case '0'..'9':
777 sscanf(str, "%d", i);
778 moreoffset=i;
779 break;
780 }
781 }
782 else
783 {
784 moreoffset=1;
785 moreflag=FALSE;
786 }
787 if(moreoffset<1)
788 moreoffset=1;
789 if(CatFile())
790 W("*** More: q,u,U,d,D,/<regexp>,<line> ["+(moreoffset-1)+"] *** ");
791 else
792 {
793 W("*** More: q,u,U,d,D,/<regexp>,<line> ["+(moreoffset-1)+"=EOF] *** ");
794 moreflag=TRUE;
795 }
796 input_to("MoreFile");
797 return;
798}
799
800// Schade eigentlich das ich es neuschreiben musste, aber es ist
801// schneller neu geschrieben als durch die undokumentieren alten Funktionen
802// durchzusteigen... *seufz*
803// Padreic
804
805static string last_file, *last_file_buffer;
806static int last_file_date, last_file_size, last_file_complete;
807
808static string sread_line(int num)
809{
810 if (!morefile) return "";
811 if (last_file!=morefile || last_file_date!=file_time(morefile)) {
812 if (!(last_file=read_bytes(morefile, 0, 50000))) return "";
813 last_file_date=file_time(morefile);
814 last_file_buffer=explode(last_file, "\n");
815 last_file_size=sizeof(last_file_buffer);
816 if (sizeof(last_file)==50000 && last_file[<1]!='\n') {
817 last_file_size--; // letzte Zeile nicht vollstaendig gelesen
818 last_file_complete=0;
819 }
820 else if (file_size(morefile)>50000)
821 last_file_complete=0;
822 else last_file_complete=1;
823 last_file=morefile;
824 }
825 if (num==0) num=1;
826 // bei zu grossen Files nicht mehr alles buffern...
827 if (num>last_file_size) {
828 if (last_file_complete) return "";
829 return (read_file(morefile, num, 1) || "");
830 }
831 return last_file_buffer[num-1]+"\n";
832}
833
834static int CatFile()
835{
836 int end;
837 string l;
838
839 end=moreoffset+morelines;
840 while(moreoffset<end)
841// if((l=read_file(morefile, moreoffset, 1))!="")
842 if((l=sread_line(moreoffset))!="")
843 {
844 moreoffset++;
845 W(l);
846 }
847 else
848 return FALSE;
849// if(read_file(morefile, moreoffset+1, 1)!="")
850 if(sread_line(moreoffset+1)!="")
851 return TRUE;
852 else
853 return FALSE;
854}
855
856static int XGrepFile(string pat, string file, int mode)
857{
858 int i, j, f, s, fsize;
859 string tfile, *tmp, *ts, t;
860
861 SECURE2(FALSE);
862 TK("XGrepFile: pat: "+pat+" file: "+file+" mode: "+mode);
863 if(!(pat&&file))
864 return FALSE;
865 tfile=TMP_FILE;
866 fsize=file_size(file);
867 for(i=0,f=0; i<fsize && t=read_bytes(file, i, 50000); i+=50000)
868 tmp=strip_explode(t,"\n");
869 if (t && t[<1]!='\n' && sizeof(t)==50000) {
870 i-=sizeof(tmp[<1]);
871 tmp=tmp[0..<2];
872 }
873 if(s=sizeof(tmp))
874 {
875 for(j=0;j<s;j++)
876 {
877 if(sizeof(ts=regexp(({(mode&XGREP_ICASE?lower_case(tmp[j]):tmp[j])}),pat)))
878 {
879 if(!(mode&XGREP_REVERT))
880 {
881 if(!f++)
882 write_file(tfile, "*** File: "+file+" ***\n");
883 write_file(tfile, tmp[j]+"\n");
884 }
885 }
886 else if(mode&XGREP_REVERT)
887 {
888 if(!f++)
889 write_file(tfile, "*** File: "+file+" ***\n");
890 write_file(tfile, tmp[j]+"\n");
891 }
892 }
893 }
894 return TRUE;
895}
896
897static void XExecFile(int line)
898{
899 int i;
900
901 if(!scriptline)
902 return;
903 for(i=line; i<scriptsize&&i<line+EXEC_LINES; i++)
904 {
905 if(!scriptline[i])
906 continue;
907 if(!Command(scriptline[i]))
908 {
909 scriptline=NULL;
910 return;
911 }
912 }
913 if(i<scriptsize)
914 call_out("XExecFile", EXEC_TIME, i);
915 else
916 scriptline=NULL;
917}
918
919static void XmtpScript(string dir, string file, string opt)
920{
921 int s, t;
922 string *files;
923
924 s=sizeof(files=get_dir(dir+"/*"));
925 while(s--)
926 {
927 t=sizeof(files[s])-1;
928 if(files[s] == ".." || files[s] == "." || files[s][t] == '~' ||
929 (files[s][0] == '#' && files[s][t] == '#'))
930 continue;
931 if(file_size(dir+"/"+files[s])==-2)
932 {
933 write_file(file, "mkdir "+files[s]+" ; cd "+files[s]+"\n");
934 XmtpScript(dir+"/"+files[s], file, opt);
935 write_file(file, "cd ..\n");
936 }
937 else
938 write_file(file, "mtp -r "+opt+" "+dir+"/"+files[s]+"\n");
939 }
940}
941
942/*----------------------------------------------------------------------
943 * player properties handling
944 */
945
946static string PlayerIdle(object obj)
947{
948 string str;
949 int i, tmp;
950
951 if(!obj)
952 return NULL;
953 if((i=query_idle(obj))>=60)
954 {
955 str=ARIGHT(""+(i/3600), 2, "0");
956 i-=(i/3600)*3600;
957 str+="'"+ARIGHT(""+(i/60), 2, "0");
958 }
959 else
960 str=".....";
961 return str;
962}
963
964static string PlayerAge(object obj)
965{
966 string str;
967 int i, tmp;
968
969 if(!obj)
970 return NULL;
971 i=(int)obj->QueryProp(P_AGE);
972 str=" "+ARIGHT(""+(i/43200), 4, ".");
973 i-=(i/43200)*43200;
974 return str+":"+ARIGHT(""+(i/1800), 2, "0");
975}
976
977static string crname(object who)
978{
979 string uid, lname;
980
981 if((uid=getuid(who))==ROOTID &&
982 object_name(who)[0..7]=="/secure/" &&
983 (lname=(string)who->loginname()))
984 return CAP(lname);
985 return CAP(uid);
986}
987
988static string PlayerWho(object obj)
989{
990 object tmp;
991 string str, stmp;
992 str=ARIGHT(""+LEVEL(obj) , 3, " ");
993 str+=ALEFT(" "+crname(obj)+" ", 12, ".");
994 str+=PlayerAge(obj);
995 str+=((int)obj->QueryProp(P_GENDER)==1 ? " m " : " f ");
996 str+=(obj->QueryProp(P_FROG)) ? "f" : ".";
997 str+=(obj->QueryProp(P_GHOST)) ? "g" : ".";
998 str+=(obj->QueryProp(P_INVIS)) ? "i" : ".";
999 str+=(query_editing(obj)||query_input_pending(obj) ? "e" : ".");
1000 str+=(obj->QueryProp(P_AWAY)) ? "a" : ".";
1001 str+=" "+PlayerIdle(obj)+" ";
1002 str+=(tmp=ENV(obj)) ? ObjFile(tmp) : "- fabric of space -";
1003 return str;
1004}
1005
1006static string PlayerMail(object obj, int flag)
1007{
1008 string pre;
1009
1010 pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
1011 return pre+"mail: "+obj->QueryProp(P_MAILADDR);
1012}
1013
1014static string PlayerIP(object obj, int flag)
1015{
1016 string pre;
1017
1018 pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
1019 return pre+"host: "+query_ip_name(obj)+" ("+query_ip_number(obj)+")";
1020}
1021
1022static string PlayerRace(object obj, int flag)
1023{
1024 string tmp, pre;
1025
1026 pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
1027 pre=pre+"race: "+ALEFT(obj->QueryProp(P_RACE)+" ", 10, ".")+" guild: ";
1028 tmp=(string)obj->QueryProp(P_GUILD);
1029 return tmp ? pre+tmp : pre+"- none -";
1030}
1031
1032static string PlayerDomain(object obj, int flag)
1033{
1034 int i, s;
1035 mixed *uinfo;
1036 string *domains, pre;
1037
1038 pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
1039 pre+="domainlord of: ";
1040 uinfo=(mixed*)MASTER->get_userinfo(getuid(obj));
1041 if(uinfo&&(domains=uinfo[3])&&(s=sizeof(domains)))
1042 {
1043 for(i=0; i<s; i++)
1044 {
1045 pre += CAP(domains[i]);
1046 if(i<s-1)
1047 pre += ", ";
1048 }
1049 }
1050 return pre;
1051}
1052
1053static string PlayerStats(object obj, int flag)
1054{
1055 string pre;
1056
1057 pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
1058 pre+="hp="+ARIGHT(obj->QueryProp(P_HP), 3, "0");
1059 pre+="/"+ARIGHT(obj->QueryProp(P_MAX_HP), 3, "0");
1060 pre+=" sp="+ARIGHT(obj->QueryProp(P_SP), 3, "0");
1061 pre+="/"+ARIGHT(obj->QueryProp(P_MAX_SP), 3, "0");
1062 pre+=" food="+ARIGHT(obj->QueryProp(P_FOOD), 3, "0");
1063 pre+="/"+ARIGHT(obj->QueryProp(P_MAX_FOOD), 3, "0");
1064 pre+=" drink="+ARIGHT(obj->QueryProp(P_DRINK), 3, "0");
1065 pre+="/"+ARIGHT(obj->QueryProp(P_MAX_DRINK), 3, "0");
1066 pre+=" exps="+obj->QueryProp(P_XP);
1067 return pre;
1068}
1069
1070static string PlayerSnoop(object obj, int flag)
1071{
1072 string tmp, pre;
1073 object victim;
1074
1075 pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
1076 pre=pre+"is snooped by: ";
1077 if(victim=query_snoop(obj))
1078 pre+=ARIGHT(" "+crname(victim), 12, ".");
1079 else
1080 pre+="............";
1081 return pre;
1082}
1083
1084static string PlayerCmdAvg(object obj, int flag)
1085{
1086 string pre;
1087
1088 pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
1089 return pre+"cmdavg: "+(int)obj->_query_command_average();
1090}
1091
1092
1093/*----------------------------------------------------------------------
1094 * msg input to objects
1095 */
1096
1097static void XMsgSay(string str)
1098{
1099 if(str=="."||str=="**")
1100 {
1101 WLN("[End of message]");
1102 say("[End of message]\n");
1103 }
1104 else
1105 {
1106 say(str+"\n");
1107 input_to("XMsgSay");
1108 }
1109}
1110
1111static void XMsgTell(string str)
1112{
1113 if(str=="."||str=="**")
1114 {
1115 WLN("[End of message]");
1116 tell_object(msgto, "[End of message]\n");
1117 }
1118 else
1119 {
1120 tell_object(msgto, str+"\n");
1121 input_to("XMsgTell");
1122 }
1123}
1124
1125static void XMsgShout(string str)
1126{
1127 if(str=="."||str=="**")
1128 {
1129 WLN("[End of message]");
1130 shout("[End of message]\n");
1131 }
1132 else
1133 {
1134 shout(str+"\n");
1135 input_to("XMsgShout");
1136 }
1137}
1138
1139/*----------------------------------------------------------------------
1140 * own object moving
1141 */
1142
1143int move(mixed dest)
1144{
1145 move_object(ME, cloner?cloner:dest);
1146 return TRUE;
1147}
1148
1149/*----------------------------------------------------------------------
1150 * object id
1151 */
1152
1153int id(string str)
1154{
1155 if(!security()&&MODE(MODE_SCANCHK)&&RTP&&!IS_ARCH(RTP))
1156 WDLN(crname(RTP)+" scanned you (id) ["+query_verb()+"] "+
1157 (PREV ? ObjFile(PREV) : "[destructed object]"));
1158 return LOWER(str)==LOWER(TOOL_NAME);
1159}
1160
1161/*----------------------------------------------------------------------
1162 * short and long description
1163 */
1164
1165string short()
1166{
1167 return _query_short()+".\n";
1168}
1169
1170string _query_short()
1171{
1172 string sh; // added by Rumata
1173 if(cloner)
1174 {
1175 if((!security())&&MODE(MODE_SCANCHK)&&!IS_ARCH(RTP))
1176 WDLN(crname(RTP)+" scanned you (short) ["+query_verb()+"] "+
1177 (PREV ? ObjFile(PREV) : "[destructed object]"));
1178 if( sh=Query(P_SHORT) ) return sh; // added by Rumata
1179 return cloner->name(WESSEN)+" "+TOOL_TITLE+" ["+
1180 ctime(time())[11..18]+"]";
1181 }
1182 return TOOL_TITLE;
1183}
1184
1185string long()
1186{
1187 return _query_long();
1188}
1189
1190string _query_long()
1191{
1192 if(cloner&&!security()&&MODE(MODE_SCANCHK)&&!IS_ARCH(RTP))
1193 {
1194 WDLN(crname(RTP)+" scanned you (long) ["+query_verb()+"] "+
1195 (PREV ? ObjFile(PREV) : "[destructed object]"));
1196 }
1197 return
1198 "This is "+TOOL_NAME+" version "+TOOL_VERSION+
1199 " (maintained by Kirk@MorgenGrauen)\n"+
1200 "Original copyright held by Hyp.\n"+
1201 "Gamedriver patchlevel: "+__VERSION__+" master object: "+__MASTER_OBJECT__+
1202 "\n\nDo 'xhelp' for more information.\n";
1203}
1204
1205string name(mixed dummy1, mixed dummy2)
1206{
1207 return _query_short();
1208}
1209
1210/*----------------------------------------------------------------------
1211 * light stuff
1212 */
1213
1214int _query_light()
1215{
1216 return xlight;
1217}
1218
1219int _set_light(int x)
1220{
1221 return xlight;
1222}
1223
1224/*----------------------------------------------------------------------
1225 * Autoloading
1226 */
1227
1228mixed *_query_autoloadobj()
1229{
1230 return AUTOLOAD_ARGS;
1231}
1232
1233void _set_autoloadobj(mixed *args)
1234{
1235 WLN(TOOL_TITLE+" ...");
1236 if(!pointerp(args))
1237 ;
1238 else if(sizeof(args)!=3)
1239 ;
1240 else if(!stringp(args[0]))
1241 ;
1242 else if(!intp(args[1]))
1243 ;
1244 else if(!intp(args[2]))
1245 ;
1246 else
1247 {
1248 if((string)args[0]!=TOOL_INTERNAL)
1249 {
1250 WLN("*****************************");
1251 WLN("*** NEW EDITION ***");
1252 WLN("*** do 'xtool news' for ***");
1253 WLN("*** more information ***");
1254 WLN("*****************************");
1255 }
1256 modi=(int)args[1];
1257 morelines=(int)args[2];
1258 return;
1259 }
1260 W("(bad autoload, using default)\n");
1261}
1262
1263/*----------------------------------------------------------------------
1264 * creation, updating and initialization stuff
1265 */
1266
1267void update_tool(mixed *args, object obj)
1268{
1269 SECURE1();
1270 if(!(obj&&args))
1271 return;
1272 Destruct(PREV);
1273 _set_autoloadobj(args);
1274 move(obj);
1275}
1276
1277void create()
1278{
1279 object obj;
1280
1281 if(member(object_name(),'#')<0)
1282 return;
1283 if(!cloner&&!((cloner=TP)||(cloner=ENV(ME)))&&!interactive(cloner))
1284 destruct(ME);
1285 if(!IS_LEARNER(cloner))
1286 destruct(ME);
1287 SetProp(P_NODROP,"Das waere zu gefaehrlich.\n");
1288 SetProp(P_NEVERDROP,1);
1289 SetProp(P_NOBUY,1);
1290 if(file_size(SAVE_FILE+".o")>0)
1291 {
1292 WDLN("Loading "+TOOL_TITLE+" settings");
1293 restore_object(SAVE_FILE);
1294 }
1295 if(MODE(MODE_FIRST))
1296 call_out("move",0,cloner);
1297 call_out("add_insert_hook",1,ME);
1298}
1299
1300void TK(string str)
1301{
1302 if (!xtk)
1303 return;
1304 tell_object(cloner,"XTOOL: "+str+"\n");
1305}
1306
1307int Xtk(string str)
1308{
1309 xtk=!xtk;
1310 WDLN("Xtool internal tracing "+(xtk?"enabled":"disabled"));
1311 return TRUE;
1312}
1313
1314void add_insert_hook(object obj)
1315{
1316 if(objectp(obj))
1317 cloner->AddInsertHook(obj);
1318}
1319
1320void init()
1321{
1322 object first, prev;
1323
1324 if(member(object_name(),'#')<0) return;
1325 first=first_inventory(ENV(ME));
1326 if(MODE(MODE_PROTECT)&&is_player(first)&&!IS_ARCH(first))
1327 {
1328 WDLN("WARNING: "+crname(first)+" tried to move into your inventory");
1329 tell_object(first, "You cannot move yourself into "+
1330 crname(cloner)+"'s inventory.\n");
1331 call_out("DropObj",0,first);
1332 return;
1333 }
1334 else if(MODE(MODE_FIRST)&&first!=ME)
1335 move(cloner);
1336 else actions();
1337}
1338
1339void DropObj(object obj)
1340{
1341 if(!obj||!objectp(obj))
1342 return;
1343 obj->move(ENV(cloner),M_NOCHECK|M_NO_SHOW);
1344}
1345
1346#define ACTIONS\
1347([\
1348 "xcallouts" : "Xcallouts";0;1,\
1349 "xcall" : "Xcall";0;1,\
1350 "xcat" : "Xcat";1;1,\
1351 "xcd" : "Xcd";0;0,\
1352 "xclean" : "Xclean";0;0,\
1353 "xclone" : "Xclone";0;0,\
1354 "xuclone" : "Xuclone";0;0,\
1355 "xcmds" : "Xcmds";0;1,\
1356 "xdbg" : "Xdbg";0;0,\
1357 "xdclean" : "Xdclean";0;0,\
1358 "xddes" : "Xddes";0;0,\
1359 "xdes" : "Xdes";0;0,\
1360 "xdest" : "Xdes";0;0,\
1361 "xdlook" : "Xdlook";0;1,\
1362 "xdo" : "Xdo";0;0,\
1363 "xdupdate" : "Xdupdate";0;0,\
1364 "xecho" : "Xecho";0;0,\
1365 "xeval" : "Xeval";0;1,\
1366 "xforall" : "Xforall";0;0,\
1367 "xgoto" : "Xgoto";0;0,\
1368 "xhbeats" : "Xhbeats";0;1,\
1369 "xgrep" : "Xgrep";1;1,\
1370 "xhead" : "Xhead";1;1,\
1371 "xhelp" : "Xhelp";0;0,\
1372 "xinventory": "Xinventory";0;1,\
1373 "xids" : "Xids";0;0,\
1374 "xinfo" : "Xinfo";0;0,\
1375 "xinherit" : "Xinherit";0;1,\
1376 "xlag" : "Xlag";0;0,\
1377 "xlight" : "Xlight";0;0,\
1378 "xload" : "Xload";0;0,\
1379 "xlook" : "Xlook";0;1,\
1380 "xlpc" : "Xlpc";0;0,\
1381 "xman" : "Xman";0;0,\
1382 "xmore" : "Xmore";1;0,\
1383 "xmove" : "Xmove";0;0,\
1384 "xmsg" : "Xmsg";1;0,\
1385 "xmtp" : "Xmtp";0;0,\
1386 "xproc" : "Xproc";0;1,\
1387 "xprof" : "Xprof";0;0,\
1388 "xprops" : "Xprops";0;1,\
1389 "xquit" : "Xquit";0;0,\
1390 "xscan" : "Xscan";0;0,\
1391 "xset" : "Xset";0;0,\
1392 "xsh" : "Xsh";0;0,\
1393 "xsort" : "Xsort";1;1,\
1394 "xtail" : "Xtail";1;1,\
1395 "xtk" : "Xtk";0;0,\
1396 "xtool" : "Xtool";0;0,\
1397 "xtrace" : "Xtrace";0;0,\
1398 "xtrans" : "Xtrans";0;0,\
1399 "xupdate" : "Xupdate";0;0,\
1400 "xwc" : "Xwc";1;0,\
1401 "xwho" : "Xwho";0;1,\
1402 ])
1403
1404static string PrepareLine(string str)
1405{
1406 return str;
1407}
1408
1409static string QuoteLine(string str)
1410{
1411 string *tmp,*tmp2;
1412 int i, i2, len, len2, qd, qs;
1413
1414 str=string_replace(str,"\\\\","°BSHL");
1415 str=string_replace(str,"\\\"","°DBLQ");
1416 str=string_replace(str,"\\\'","°SGLQ");
1417 str=string_replace(str,"\\|","°PIPE");
1418 str=string_replace(str,"||","°OROR");
1419 str=string_replace(str,"->","°LARR");
1420 str=string_replace(str,"\\$","°DOLR");
1421 tmp=regexplode(str,"(\"|')");
1422 len=sizeof(tmp);
1423 qd=qs=0;
1424 for(i=0;i<len;i++)
1425 {
1426 if(i%2)
1427 {
1428 if(tmp[i]=="'")
1429 qd=(!qs?!qd:qd);
1430 else
1431 qs=(!qd?!qs:qs);
1432 if((tmp[i]=="\""&&!qd)||(tmp[i]=="'"&&!qs))
1433 tmp[i]="";
1434 }
1435 else
1436 {
1437 if(!qd)
1438 {
1439 len2=sizeof(tmp2=regexplode(tmp[i],"\\$[^ ][^ ]*"));
1440 for(i2=0;i2<len2;i2++)
1441 if(i2%2)
1442 {
1443 TK("QuoteLine: "+tmp2[i2][1..]);
1444 tmp2[i2]=(string)XFindObj((tmp2[i2])[1..]);
1445 }
1446 tmp[i]=implode(tmp2,"");
1447 }
1448 }
1449 }
1450 if(qd||qs)
1451 return NULL;
1452 str=implode(tmp,"");
1453 TK("QuoteLine: str: "+str);
1454 return str;
1455}
1456
1457static string UnquoteLine(string str)
1458{
1459 str=string_replace(str,"°BSHL","\\");
1460 str=string_replace(str,"°DBLQ","\"");
1461 str=string_replace(str,"°SGLQ","\'");
1462 str=string_replace(str,"°DQUO","");
1463 str=string_replace(str,"°SQUO","");
1464 str=string_replace(str,"°PIPE","|");
1465 str=string_replace(str,"°OROR","||");
1466 str=string_replace(str,"°LARR","->");
1467 str=string_replace(str,"°DOLR","$");
1468 TK("UnquoteLine: str: "+str);
1469 return str;
1470}
1471
1472static string *ExplodeCmds(string str)
1473{
1474 string *tmp;
1475
1476 tmp=regexplode(str,"\\||>|>>");
1477 while(tmp[<1]=="")
1478 tmp=tmp[0..<2];
1479 return tmp;
1480}
1481
1482varargs int ParseLine(string str)
1483{
1484 string verb, arg;
1485 int ret;
1486
1487 TK("ParseLine: str: "+(str?str:""));
1488 if(!sizeof(cmds))
1489 {
1490 // this is a single command or beginning of a command pipe
1491 verb=query_verb();
1492
1493 // return on unknown commands
1494 if(!verb||!sizeof(verb)||!GetFunc(verb,TRUE))
1495 return FALSE;
1496
1497 str=(string)this_player()->_unparsed_args();
1498 pipe_in=FALSE;
1499 pipe_of=NULL;
1500 pipe_ovr=TRUE;
1501 pipe_out=FALSE;
1502 pipe_of=NULL;
1503 // pass arguments to some special functions unparsed
1504 if(member(({"xlpc","xcall","xeval"}),verb)>=0)
1505 {
1506#ifdef XDBG
1507 TK("ParseLine: special func: "+verb);
1508#endif
1509 ret=CallFunc(verb,str);
1510 SafeReturn(ret);
1511 }
1512 // ok, here we go
1513 pipe_in=pipe_out=FALSE;
1514 pipe_if=pipe_of=NULL;
1515 pipe_ovr=TRUE;
1516 if(file_size(PIPE_FILE)>=0)
1517 rm(PIPE_FILE);
1518 if (str&&str!="")
1519 {
1520 if(!(str=QuoteLine(str)))
1521 {
1522 WDLN("Unterminated quotation");
1523 SafeReturn(TRUE);
1524 }
1525 cmds=ExplodeCmds(str);
1526 }
1527 else
1528 cmds=({""});
1529 arg=strip_string(cmds[0]);
1530 }
1531 else
1532 {
1533 cmds[0]=strip_string(cmds[0]);
1534 TK("ParseLine: cmds[0]: "+cmds[0]);
1535 if(sscanf(cmds[0],"%s %s",verb,arg)!=2)
1536 {
1537 verb=cmds[0];
1538 arg="";
1539 }
1540 }
1541 cmds=cmds[1..];
1542 TK("ParseLine: verb: "+verb);
1543 if (!verb||!sizeof(verb)||!GetFunc(verb,TRUE))
1544 SafeReturn(FALSE);
1545 TK("ParseLine(1): arg: "+arg+" cmds: "+sprintf("%O",cmds));
1546 switch(sizeof(cmds))
1547 {
1548 case 0:
1549 ret=CallFunc(verb,strip_string(UnquoteLine(arg)));
1550 SafeReturn(ret);
1551 break;
1552
1553 case 1:
1554 WDLN("Missing rhs of command pipe");
1555 SafeReturn(TRUE);
1556 break;
1557
1558 default:
1559 pipe_out=TRUE;
1560 switch(cmds[0])
1561 {
1562 case "|":
1563 pipe_of=PIPE_FILE;
1564 pipe_ovr=TRUE;
1565 cmds=cmds[1..];
1566 break;
1567
1568 case ">":
1569 pipe_ovr=TRUE;
1570 if(sizeof(cmds)!=2)
1571 {
1572 WDLN("Illegal IO redirection");
1573 SafeReturn(TRUE);
1574 }
1575 pipe_of=cmds[1];
1576 cmds=({});
1577 break;
1578
1579 case ">>":
1580 pipe_ovr=FALSE;
1581 if(sizeof(cmds)!=2)
1582 {
1583 WDLN("Illegal IO redirection");
1584 SafeReturn(TRUE);
1585 }
1586 pipe_of=cmds[1];
1587 cmds=({});
1588 break;
1589 }
1590 }
1591 TK("ParseLine(2): arg: "+arg+" cmds: "+sprintf("%O",cmds));
1592 if(!CallFunc(verb,strip_string(arg)))
1593 SafeReturn(FALSE);
1594 pipe_in=pipe_out;
1595 pipe_if=pipe_of;
1596 pipe_ovr=FALSE;
1597 pipe_out=FALSE;
1598 pipe_of=NULL;
1599 if(sizeof(cmds))
1600 call_out("ParseLine",0);
1601 else
1602 SafeReturn(TRUE);
1603 return TRUE;
1604}
1605
1606static int CallFunc(string verb, string str)
1607{
1608 string fun;
1609
1610 fun=GetFunc(verb,FALSE);
1611#ifdef XDBG
1612 TK("CallFunc: verb: "+verb+" str: "+str);
1613 TK("CallFunc: resolved function: "+(fun?fun:"(unresolved)"));
1614#endif
1615 if(str=="")
1616 str=NULL;
1617 return fun?(int)call_other(ME,fun,str):FALSE;
1618}
1619
1620static string GetFunc(string verb, int test)
1621{
1622 string fun,*keys,key;
1623 int i,len;
1624
1625 TK("GetFunc: verb: "+verb);
1626
1627 if(verb[0..0]!="x") // Assume all commands start with "x"
1628 return 0;
1629
1630 if (!(fun=(string)ACTIONS[verb,0])) { // Try exact hit first
1631 key="";
1632 len=sizeof(verb);
1633 for (i=sizeof(keys=m_indices(ACTIONS))-1;i>=0;i--) {
1634 TK(" trying: "+keys[i]);
1635 if(sizeof(keys[i])>=len&&keys[i][0..len-1]==verb) {
1636 if(sizeof(key)) {
1637 WLN("Das ist nicht eindeutig ...");
1638 return 0;
1639 }
1640 fun=ACTIONS[keys[i],0];
1641 key=keys[i];
1642 //break;
1643 }
1644 }
1645 } else
1646 key=verb;
1647
1648 if(test)
1649 return fun;
1650
1651 if (key) {
1652#ifdef XDBG
1653 TK("GetFunc: fun: "+fun+" (key: "+key+")\n"+
1654 "pipe_in: "+(pipe_in?"TRUE ":"FALSE ")+(pipe_if?pipe_if:"(NULL)")+"\n"+
1655 "pipe_out: "+(pipe_out?"TRUE ":"FALSE ")+(pipe_of?pipe_of:"(NULL)")+"\n"+
1656 "pipe_ovr: "+(pipe_ovr?"TRUE":"FALSE"));
1657#endif
1658 if (pipe_in&&!ACTIONS[key,PIPE_IN])
1659 {
1660 // this command does not read pipes
1661#ifdef XDBG
1662 TK("Illegal rhs of command pipe \""+fun+"\"\n");
1663#endif
1664 notify_fail("Illegal rhs of command pipe \""+fun+"\"\n");
1665 return 0;
1666 }
1667 else if (pipe_out&&!ACTIONS[key,PIPE_OUT])
1668 {
1669 // this command does not feed pipes
1670#ifdef XDBG
1671 TK("Illegal lhs of command pipe \""+fun+"\"\n");
1672#endif
1673 notify_fail("Illegal lhs of command pipe \""+fun+"\"\n");
1674 return 0;
1675 }
1676 }
1677 return fun;
1678}
1679
1680void actions()
1681{
1682 if (!cloner||!RTP||cloner==RTP||query_wiz_level(cloner)<=query_wiz_level(RTP))
1683 add_action("ParseLine","",1);
1684 add_action("CommandScan", "", 1);
1685}
1686
1687/*----------------------------------------------------------------------
1688 * the checking stuff
1689 */
1690
1691void InsertNotify(object obj)
1692{
1693 if(!cloner)
1694 return;
1695 if(MODE(MODE_FIRST) && find_call_out("move")==-1)
1696 call_out("move",0,cloner);
1697 if(MODE(MODE_INVCHECK))
1698 write_newinvobj(obj);
1699}
1700
1701static void VarCheck(int show)
1702{
1703 int i, s;
1704 foreach(string k, mixed v : variable)
1705 {
1706 if (v) continue;
1707 if(show) WDLN("*** Variable $"+k+" has been destructed");
1708 m_delete(variable, k);
1709 }
1710}
1711
1712
1713int write_newinvobj(object obj)
1714{
1715 if(obj) WDLN("*** New object in inventory "+ObjFile(obj));
1716 return(1);
1717}
1718
1719/*----------------------------------------------------------------------
1720 * catch all commands, absorb forces and check history
1721 */
1722
1723int CommandScan(string arg)
1724{
1725 string verb, cmd;
1726 object rtp;
1727 rtp=RTP;
1728
1729 if(!cloner&&!(cloner=rtp)) destruct(ME);
1730
1731 if((!MODE(MODE_PROTECT))||security()||
1732 query_wiz_level(cloner)<query_wiz_level(rtp))
1733 {
1734 verb=query_verb();
1735 if(verb&&DoHistory(verb+(arg ? " "+arg : "")))
1736 return TRUE;
1737 nostore=FALSE;
1738 return FALSE;
1739 }
1740 else
1741 {
1742 if(rtp)
1743 {
1744 WDLN("Your "+TOOL_TITLE+" protects you from a force by "+crname(rtp)+
1745 " ["+query_verb()+(arg ? " "+arg+"]" : "]"));
1746 tell_object(rtp, crname(cloner)+"'s "+TOOL_TITLE+
1747 " absorbes your force.\n");
1748 }
1749 else
1750 {
1751 WDLN("Your "+TOOL_TITLE+" protects you from a force ["+
1752 query_verb()+(arg ? " "+arg+"]" : "]"));
1753 }
1754 return TRUE;
1755 }
1756}
1757
1758int DoHistory(string line)
1759{
1760 int i;
1761 string cmd, *strs;
1762
1763 SECURE2(FALSE);
1764 if(!stringp(line) || !sizeof(line))
1765 return TRUE;
1766 else if(line=="%!")
1767 {
1768 WLN("Current command history:");
1769 for(i=MAX_HISTORY; i; --i)
1770 if(history[i-1])
1771 {
1772 W(" "+ARIGHT(""+i, 2, " ")+": ");
1773 if(sizeof(history[i-1])>70)
1774 WLN(ALEFT(history[i-1], 70, " "));
1775 else
1776 WLN(history[i-1]);
1777 }
1778 return TRUE;
1779 }
1780 else if(line[0..1]=="%%" && (cmd=history[0]+line[2..<1]))
1781 {
1782 Command(cmd);
1783 return TRUE;
1784 }
1785 else if(line[0]=='^'&&(strs=strip_explode(line, "^")))
1786 {
1787 if(sizeof(strs)&&strs[0]&&(cmd=history[0]))
1788 {
1789 if(sizeof(strs)==2)
1790 cmd=string_replace(cmd, strs[0], strs[1]);
1791 else
1792 cmd=string_replace(cmd, strs[0], "");
1793 nostore--;
1794 Command(cmd);
1795 nostore++;
1796 return TRUE;
1797 }
1798 }
1799 else if(line[0]=='%' && (sscanf(line[1..<1], "%d", i)))
1800 {
1801 i= i>0 ? i : 1;
1802 i= i<=MAX_HISTORY ? i : MAX_HISTORY;
1803 if(cmd=history[i-1])
1804 Command(cmd);
1805 return TRUE;
1806 }
1807 else if(line[0]=='%')
1808 {
1809 for(i=0; i<MAX_HISTORY; i++)
1810 {
1811 if(history[i]&&
1812 history[i][0..sizeof(line)-2]==line[1.. <1])
1813 {
1814 Command(history[i]);
1815 return TRUE;
1816 }
1817 }
1818 }
1819 else if(nostore<1)
1820 history=({line})+history[0..MAX_HISTORY-2];
1821 return FALSE;
1822}
1823