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