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