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