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