blob: 4656d6814d2d0079c40601ab9fdf94de9c010e6d [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 {
286 if(object_name(obj)[0..26]=="/d/unterwelt/objekte/teddy#" &&
287 IS_ARCH(this_interactive()))
288 str="Ein Teddy (stumm)";
289 else
290 {
bugfixaf2be4f2020-03-22 19:13:07 +0100291 if(str=({string})obj->QueryProp(P_INT_LONG))
MG Mud User88f12472016-06-24 23:31:02 +0200292 ;
bugfixaf2be4f2020-03-22 19:13:07 +0100293 else if(str=({string})obj->QueryProp(P_LONG))
MG Mud User88f12472016-06-24 23:31:02 +0200294 ;
295 else
296 str="- no long description -\n";
297 }
298 }
299 if(!file||file=="")
300 W(str);
301 else
302 write_file(file,str);
303 FORALL(item, obj)
304 {
305 if(!i)
306 if(!file||file=="")
307 WLN("Content:");
308 else
309 write_file(file,"Content:\n");
310 PrintShort(ARIGHT(++i+". ", 4, " "), item, file);
311 }
312}
313
314static string ObjFile(object obj)
315{
316 return "["+short_path(object_name(obj))+"]";
317}
318
319static varargs void PrintShort(string pre, object obj, string file)
320{
321 string str;
322
323 SECURE1();
324 if(!obj)
325 return;
326 if(MODE(MODE_SHORT))
327 {
328 if (query_once_interactive(obj))
329 str=capitalize(getuid(obj));
330 else
331 {
bugfixaf2be4f2020-03-22 19:13:07 +0100332 if(!((str=({string})obj->QueryProp(P_INT_SHORT))||
333 (str=({string})obj->QueryProp(P_SHORT))))
MG Mud User88f12472016-06-24 23:31:02 +0200334 if(is_player(obj))
335 str=CRNAME(obj)+" (invisible)";
336 else
337 str="- no short description -";
338 }
339 str=ALEFT(sprintf("%O ",str), 34, ".")+" ";
340 }
341 else
342 str="";
343 if(interactive(obj))
344 str+="i";
345 else if(living(obj))
346 str+="l";
347 else
348 str+=".";
349 str+=(shadow(obj, 0) ? "s" : ".");
350 if(!file||file=="")
351 WLN((pre+CAP(str)+" "+ObjFile(obj))[0..79]);
352 else
353 write_file(file,(pre+CAP(str)+" "+ObjFile(obj))[0..79]+"\n");
354}
355
356static varargs void DeepPrintShort(object env, int indent, string pre, string file)
357{
358 int i;
359 object item;
360 string str;
361
362 SECURE1();
363 if(!env)
364 return;
365 for(i=indent,str=""; i--; str+=" ");
366 if(pre)
367 str+=pre;
368 if(!file||file=="")
369 W(str);
370 else
371 write_file(file,str);
372 i++;
373 PrintShort("",env,file);
374 FORALL(item, env)
375 DeepPrintShort(item,indent+1,ARIGHT((++i)+". ",4," "),file);
376}
377
378static string break_string_hard(string str, int len, string pre)
379{
380 int s,p,t;
381 string tmp;
382
383 if(!str||!(s=sizeof(str)))
384 return "";
385 t=len-(p=sizeof(pre))-1;
386
387 tmp="";
388 while(p+s>len)
389 {
390 tmp+=pre+str[0..t]+"\n";
391 str=str[t+1..];
392 s-=t;
393 }
394 if(sizeof(str))
395 tmp+=pre+str[0..]+"\n";
396 return tmp;
397}
398
399static void dprop(string key, mixed data, object obj)
400{
401 if(pipe_out&&pipe_of)
402 write_file(pipe_of,break_string_hard(mixed_to_string(obj->QueryProp(key),MAX_RECURSION),78,ALEFT(key+" ",18,".")+" = "));
403 else
404 W(break_string_hard(mixed_to_string(obj->QueryProp(key),MAX_RECURSION),78,ALEFT(key+" ",18,".")+" = "));
405}
406
407static string propflags(string key, object ob)
408{
409 int tmp;
410 string *flags;
bugfixaf2be4f2020-03-22 19:13:07 +0100411 tmp=({mixed})ob->Query(key,1);
MG Mud User88f12472016-06-24 23:31:02 +0200412 flags=({});
413 tmp&SAVE ? flags+=({"SAV"}) : flags+=({" "});
414 tmp&PROTECTED ? flags+=({"PRO"}) : flags+=({" "});
415 tmp&SECURED ? flags+=({"SEC"}) : flags+=({" "});
416 tmp&NOSETMETHOD ? flags+=({"NSM"}) : flags+=({" "});
417 tmp&SETMNOTFOUND ? flags+=({"SMN"}) : flags+=({" "});
418 tmp&QUERYMNOTFOUND ? flags+=({"QMN"}) : flags+=({" "});
419 tmp&QUERYCACHED ? flags+=({"QCA"}) : flags+=({" "});
420 tmp&SETCACHED ? flags+=({"SCA"}) : flags+=({" "});
421 return ""+implode(flags,"|");
422}
423
424static void dprop2(string key, mixed data, object ob)
425{
426 if(pipe_out&&pipe_of)
427 write_file(pipe_of,break_string_hard(mixed_to_string(propflags(key,ob),MAX_RECURSION),78,ALEFT(key+" ",18,".")+" = "));
428 else
429 W(break_string_hard(mixed_to_string(propflags(key,ob),MAX_RECURSION),78,ALEFT(key+" ",18,".")+" = "));
430}
431
432static mixed propmethods(string key, object ob)
433{
bugfixaf2be4f2020-03-22 19:13:07 +0100434 return ({mixed})ob->Query(key,2);
MG Mud User88f12472016-06-24 23:31:02 +0200435}
436
437static void dprop3(string key, mixed data, object ob)
438{
439 if(pipe_out&&pipe_of)
440 write_file(pipe_of,break_string_hard(mixed_to_string(propmethods(key,ob),MAX_RECURSION),78,ALEFT(key+" ",18,".")+" = "));
441 else
442 W(break_string_hard(mixed_to_string(propmethods(key,ob),MAX_RECURSION),78,ALEFT(key+" ",18,".")+" = "));
443}
444
445static void DumpProperties(object obj, int flag)
446{
447 SECURE1();
448 if(!obj)
449 return;
450 PIPE_DELETE(pipe_of);
451 switch (flag) {
452 case 0:
bugfixaf2be4f2020-03-22 19:13:07 +0100453 walk_mapping(((({mixed*})obj->__query_properties()))[0],#'dprop,obj);
MG Mud User88f12472016-06-24 23:31:02 +0200454 break;
455 case 1:
bugfixaf2be4f2020-03-22 19:13:07 +0100456 walk_mapping(((({mixed*})obj->__query_properties()))[0],#'dprop2,obj);
MG Mud User88f12472016-06-24 23:31:02 +0200457 break;
458 case 2:
bugfixaf2be4f2020-03-22 19:13:07 +0100459 walk_mapping(((({mixed*})obj->__query_properties()))[0],#'dprop3,obj);
MG Mud User88f12472016-06-24 23:31:02 +0200460 break;
461 }
462}
463
464/*----------------------------------------------------------------------
465 * moving objects
466 */
467
468static int MoveObj(object obj1, object obj2, int silent)
469{
470 int err;
471 object oldenv;
472
473 SECURE2(FALSE);
474 if(!(obj1&&obj2))
475 return FALSE;
476 oldenv=ENV(obj1);
bugfixaf2be4f2020-03-22 19:13:07 +0100477 err=({int})obj1->move(obj2, M_SILENT|M_NOCHECK);
MG Mud User88f12472016-06-24 23:31:02 +0200478 if(!silent)
479 switch(err)
480 {
481 case ME_PLAYER:
482 WDLN("Object returned ME_PLAYER");
483 if(oldenv && oldenv != ENV(obj1))
484 WDLN("Object has been moved");
485 return FALSE;
486 case ME_TOO_HEAVY:
487 WDLN("Object returned ME_TOO_HEAVY");
488 if(oldenv && oldenv != ENV(obj1))
489 WDLN("Object has been moved");
490 return FALSE;
491 case ME_CANT_TPORT_IN:
492 WDLN("Object returned ME_CANT_TPORT_IN");
493 if(oldenv && oldenv != ENV(obj1))
494 WDLN("Object has been moved");
495 return FALSE;
496 case ME_CANT_TPORT_OUT:
497 WDLN("Object returned ME_CANT_TPORT_OUT");
498 if(oldenv && oldenv != ENV(obj1))
499 WDLN("Object has been moved");
500 return FALSE;
501 default:
502 WDLN("Object returned unknown return value");
503 return FALSE;
504 }
505 return TRUE;
506}
507
508/*----------------------------------------------------------------------
509 * save destructing of objects
510 */
511
512static void Destruct(object obj)
513{
514 if(!obj || !this_object())
515 return;
bugfixaf2be4f2020-03-22 19:13:07 +0100516 catch(({int})obj->remove());
MG Mud User88f12472016-06-24 23:31:02 +0200517 if(objectp(obj) && !query_once_interactive(obj))
518 destruct(obj);
519}
520
521static void DeepClean(object obj)
522{
523 if(!obj)
524 return;
525 filter(filter(deep_inventory(obj), "is_not_player", ME),
526 "Destruct", ME);
527 if(is_not_player(obj))
528 Destruct(obj);
529}
530
531/*----------------------------------------------------------------------
532 * Show the inheritance tree of objects
533 */
534
535static object *SubNodes(object obj)
536{
537 int s;
538 object *objs;
539 string *inlist;
540
541 if(!obj)
542 return NULL;
543 inlist=inherit_list(obj);
544 s=sizeof(inlist);
545 objs=({});
546 while(s-->1)
547 objs=({find_object(inlist[s])})+objs;
548 return objs;
549}
550
551static void Inheritance(object obj, string func, string pre)
552{
553 int i, s;
554 object *ln;
555 string str;
556
557 if(!obj)
558 return;
559 str=pre+" "+ObjFile(obj);
560 if(func)
561 {
562 str=ALEFT(str+" ", 50, ".");
563 if(function_exists(func, obj)==object_name(obj))
564 str+=ARIGHT(" "+func, 19, ".");
565 else
566 str+=ARIGHT("", 19, ".");
567 }
568 if(pipe_out&&pipe_of)
569 write_file(pipe_of,str+"\n");
570 else
571 WLN(str);
572 ln=SubNodes(obj);
573 for(i=0; i<sizeof(ln); i++)
574 ln=ln-SubNodes(ln[i]);
575 s=sizeof(ln);
576 for(i=0; i<s; i++)
577 Inheritance(ln[i], func, pre+".....");
578}
579
580/*----------------------------------------------------------------------
581 * file name handling
582 */
583
584static string XFile(string file)
585{
586 TK("XFile: file: "+(file?file:"(NULL)"));
587 if(file)
588 switch(file[0])
589 {
590 case '@':
591 return source_file_name(XFindObj(file[1..<1]));
592 case '$':
593 return source_file_name(XFindObj(file));
594 default:
595 return old_explode(long_path(file),"#")[0];
596 }
597 return NULL;
598}
599
600static string XFindFile(string file)
601{
602 TK("XFindFile: file: "+(file?file:"(NULL)"));
603 if(file=XFile(file))
604 {
605 if(file_size(file)>=0)
606 return file;
607 if(file[<3..<1]!=".c" && file_size(file+".c")>0)
608 return file+".c";
609 }
610 WDLN("File not found or not readable ["+short_path(file)+"]");
611 return NULL;
612}
613
614/*----------------------------------------------------------------------
615 * file printing, searching and executing
616 */
617
618static void XMoreFile(string file, int flag)
619{
620 int s,size;
621
622 SECURE1();
623 if(!file)
624 return;
625
626 // term=(string)cloner->QueryProp(P_TTY)!="dumb";
627 if((size=(file_size(morefile=long_path(file))))>0)
628 {
629 if(size>100000)
630 WDLN("Warning: large file");
631 MoreFile(NULL);
632 }
633 else if(flag)
634 WDLN("Cannot read file");
635}
636
MG Mud User88f12472016-06-24 23:31:02 +0200637
638static void MoreFile(string str)
639{
640 int i, off;
641 string f, l, r;
642
643 SECURE1();
644
645 if (str /*&& sizeof(str)*/)
646 {
647 if( !sizeof(str) ) str="\0";
648 if(term)
649 W("M");
650 switch(str[0])
651 {
652 case 'q':
653 case 'x':
654 moreflag=FALSE;
655 moreoffset=1;
656 if(morefile==TMP_FILE||morefile==PIPE_FILE)
657 rm(morefile);
658 return NULL;
659 break;
660 case 'P':
661 case 'U':
662 moreflag=FALSE;
663 moreoffset=moreoffset-morelines;
664 case 'p':
665 case 'u':
666 moreoffset=moreoffset-2*morelines;
667 break;
668 case 'D':
669 case 'N':
670 moreoffset+=morelines;
671 case 0: /* RETURN */
672 case 'd':
673 if(moreflag)
674 {
675 moreflag=FALSE;
676 moreoffset=1;
677 if(morefile==TMP_FILE)
678 rm(morefile);
679 return;
680 }
681 break;
682 case '/':
683 moreoffset--;
684 more_searchexpr=str[1..<1];
685 case 'n':
686 i=moreoffset-morelines+1;
687 if(more_searchexpr=="")
688 {
689 WDLN("No previous regular expression");
690 return;
691 }
692 if(!regexp(({"dummy"}), more_searchexpr))
693 WDLN("Bad regular expression");
694 else
695 while((l=read_file(morefile, i++, 1))&&
696 !sizeof(regexp(({l}), more_searchexpr)))
697 ;
698 if(l)
699 {
700 WLN("*** Skipping ...");
701 moreoffset=i-1;
702 }
703 else
704 {
705 WLN("*** Pattern not found");
706 moreoffset-=morelines;
707 }
708 break;
709 case '0'..'9':
710 sscanf(str, "%d", i);
711 moreoffset=i;
712 break;
713 }
714 }
715 else
716 {
717 moreoffset=1;
718 moreflag=FALSE;
719 }
720 if(moreoffset<1)
721 moreoffset=1;
722 if(CatFile())
723 W("*** More: q,u,U,d,D,/<regexp>,<line> ["+(moreoffset-1)+"] *** ");
724 else
725 {
726 W("*** More: q,u,U,d,D,/<regexp>,<line> ["+(moreoffset-1)+"=EOF] *** ");
727 moreflag=TRUE;
728 }
729 input_to("MoreFile");
730 return;
731}
732
733// Schade eigentlich das ich es neuschreiben musste, aber es ist
734// schneller neu geschrieben als durch die undokumentieren alten Funktionen
735// durchzusteigen... *seufz*
Zesstra9f0401a2019-11-06 22:06:02 +0100736// Padreic
737
738// +++ Kommentarlos: Programmierer schreibt unverstaendlichen Code neu,
739// indem er unverstaendlichen Code schreibt. +++
740// +++ Kommentarlos: Programmierer ersetzt unverstaendlichen Code durch
741// unverstaendlichen Code. +++
742// Arathorn (mit Zesstra im Sinn)
MG Mud User88f12472016-06-24 23:31:02 +0200743
Zesstracda79c22019-11-06 23:42:13 +0100744// Zustandsvariablen fuer den Cache von sread_line.
745static string last_file, *last_file_lines;
746static int last_file_date, last_file_linecount, last_file_complete;
MG Mud User88f12472016-06-24 23:31:02 +0200747
Zesstracda79c22019-11-06 23:42:13 +0100748// Liest die ersten x Bytes des Files ein und cached diese (aber nur
749// vollstaendige Zeilen). Liefert dann gewuenschte Zeilen aus dem Cache ohne
750// Plattenzugriff.
751protected string sread_line(int num)
MG Mud User88f12472016-06-24 23:31:02 +0200752{
753 if (!morefile) return "";
Zesstracda79c22019-11-06 23:42:13 +0100754 // wenn sich das morefile geaendert hat, wird das neue File eingelesen.
755 if (last_file!=morefile || last_file_date!=file_time(morefile))
756 {
757 bytes byte_buf=read_bytes(morefile, 0,
758 driver_info(DI_CURRENT_RUNTIME_LIMITS)[LIMIT_BYTE]);
759 if (!byte_buf) return "";
760 // letzte unvollstaendige Zeile abschneiden
761 int linebreak_index = strrstr(byte_buf, b"\n");
762 if (linebreak_index > -1
763 && linebreak_index < sizeof(byte_buf)-1 )
764 {
765 byte_buf = byte_buf[0..linebreak_index];
766 // dann ist das File auch unvollstaendig.
767 last_file_complete=0;
MG Mud User88f12472016-06-24 23:31:02 +0200768 }
Zesstracda79c22019-11-06 23:42:13 +0100769 // aber auch wenn byte_buf mit Zeilenumbruch endet, noch schauen, ob das
770 // File nicht laenger ist als byte_buf.
771 else if (sizeof(byte_buf) < file_size(morefile))
772 last_file_complete=0;
773 // ansonsten ist es vollstaendig.
774 else
775 last_file_complete=1;
776
777 // In string konvertieren und cache speichern.
778 last_file = to_text(byte_buf, "UTF-8");
779 last_file_lines = explode(last_file, "\n");
780 // und Daten vom gecachten File speichern
781 last_file_linecount=sizeof(last_file_lines);
782 last_file_date=file_time(morefile);
783 last_file = morefile; //speichert jetzt den Filenamen
MG Mud User88f12472016-06-24 23:31:02 +0200784 }
785 if (num==0) num=1;
Zesstracda79c22019-11-06 23:42:13 +0100786
787 // wenn die angefragte Zeile nicht da ist und das File nicht vollstaendig
788 // ist, wird direkt von der Platte gelesen.
789 if (num > last_file_linecount)
790 {
MG Mud User88f12472016-06-24 23:31:02 +0200791 if (last_file_complete) return "";
Zesstracda79c22019-11-06 23:42:13 +0100792 return read_file(morefile, num, 1) || "";
MG Mud User88f12472016-06-24 23:31:02 +0200793 }
Zesstracda79c22019-11-06 23:42:13 +0100794 // Sonst kommt die Zeile aus dem Cache.
795 return last_file_lines[num-1]+"\n";
MG Mud User88f12472016-06-24 23:31:02 +0200796}
797
798static int CatFile()
799{
800 int end;
801 string l;
802
803 end=moreoffset+morelines;
804 while(moreoffset<end)
MG Mud User88f12472016-06-24 23:31:02 +0200805 if((l=sread_line(moreoffset))!="")
806 {
807 moreoffset++;
808 W(l);
809 }
810 else
811 return FALSE;
Zesstrab25537b2019-11-06 23:36:23 +0100812
MG Mud User88f12472016-06-24 23:31:02 +0200813 if(sread_line(moreoffset+1)!="")
814 return TRUE;
815 else
816 return FALSE;
817}
818
819static int XGrepFile(string pat, string file, int mode)
820{
MG Mud User88f12472016-06-24 23:31:02 +0200821 SECURE2(FALSE);
822 TK("XGrepFile: pat: "+pat+" file: "+file+" mode: "+mode);
823 if(!(pat&&file))
824 return FALSE;
Zesstra9f0401a2019-11-06 22:06:02 +0100825
826 // max. Anzahl von Zeilen pro Portion (ueberschlag: 100 Bytes pro Zeile)
827 int maxlines = driver_info(DI_CURRENT_RUNTIME_LIMITS)[LIMIT_FILE] / 100;
828 int start;
829 string buf;
830 // File portionsweise einlesen und verarbeiten
831 while(buf = read_file(file, start, maxlines))
832 {
833 string *lines = strip_explode(buf,"\n");
834 int f; // Pro Treffer erhoeht, benutzt zur einmaligen Ausgabe des Files
835 // ueber alle Zeilen laufen und regexpen
836 foreach(string line : lines)
MG Mud User88f12472016-06-24 23:31:02 +0200837 {
Zesstra9f0401a2019-11-06 22:06:02 +0100838 string *ts=regexp(({(mode&XGREP_ICASE?lower_case(line):line)}),
839 pat);
840 if(sizeof(ts))
MG Mud User88f12472016-06-24 23:31:02 +0200841 {
Zesstra9f0401a2019-11-06 22:06:02 +0100842 if(!(mode&XGREP_REVERT))
843 {
844 if(!f++)
845 write_file(TMP_FILE, "*** File: "+file+" ***\n");
846 write_file(TMP_FILE, line+"\n");
847 }
848 }
849 else if(mode&XGREP_REVERT)
850 {
851 if(!f++)
852 write_file(TMP_FILE, "*** File: "+file+" ***\n");
853 write_file(TMP_FILE, line+"\n");
MG Mud User88f12472016-06-24 23:31:02 +0200854 }
855 }
Zesstra9f0401a2019-11-06 22:06:02 +0100856 if (sizeof(lines) < maxlines)
857 break;
858 else
859 start += sizeof(lines);
860 }
MG Mud User88f12472016-06-24 23:31:02 +0200861 return TRUE;
862}
863
864static void XExecFile(int line)
865{
866 int i;
867
868 if(!scriptline)
869 return;
870 for(i=line; i<scriptsize&&i<line+EXEC_LINES; i++)
871 {
872 if(!scriptline[i])
873 continue;
874 if(!Command(scriptline[i]))
875 {
876 scriptline=NULL;
877 return;
878 }
879 }
880 if(i<scriptsize)
881 call_out("XExecFile", EXEC_TIME, i);
882 else
883 scriptline=NULL;
884}
885
886static void XmtpScript(string dir, string file, string opt)
887{
888 int s, t;
889 string *files;
890
891 s=sizeof(files=get_dir(dir+"/*"));
892 while(s--)
893 {
894 t=sizeof(files[s])-1;
895 if(files[s] == ".." || files[s] == "." || files[s][t] == '~' ||
896 (files[s][0] == '#' && files[s][t] == '#'))
897 continue;
898 if(file_size(dir+"/"+files[s])==-2)
899 {
900 write_file(file, "mkdir "+files[s]+" ; cd "+files[s]+"\n");
901 XmtpScript(dir+"/"+files[s], file, opt);
902 write_file(file, "cd ..\n");
903 }
904 else
905 write_file(file, "mtp -r "+opt+" "+dir+"/"+files[s]+"\n");
906 }
907}
908
909/*----------------------------------------------------------------------
910 * player properties handling
911 */
912
913static string PlayerIdle(object obj)
914{
915 string str;
916 int i, tmp;
917
918 if(!obj)
919 return NULL;
920 if((i=query_idle(obj))>=60)
921 {
922 str=ARIGHT(""+(i/3600), 2, "0");
923 i-=(i/3600)*3600;
924 str+="'"+ARIGHT(""+(i/60), 2, "0");
925 }
926 else
927 str=".....";
928 return str;
929}
930
931static string PlayerAge(object obj)
932{
933 string str;
934 int i, tmp;
935
936 if(!obj)
937 return NULL;
bugfixaf2be4f2020-03-22 19:13:07 +0100938 i=({int})obj->QueryProp(P_AGE);
MG Mud User88f12472016-06-24 23:31:02 +0200939 str=" "+ARIGHT(""+(i/43200), 4, ".");
940 i-=(i/43200)*43200;
941 return str+":"+ARIGHT(""+(i/1800), 2, "0");
942}
943
944static string crname(object who)
945{
946 string uid, lname;
947
948 if((uid=getuid(who))==ROOTID &&
949 object_name(who)[0..7]=="/secure/" &&
bugfixaf2be4f2020-03-22 19:13:07 +0100950 (lname=({string})who->loginname()))
MG Mud User88f12472016-06-24 23:31:02 +0200951 return CAP(lname);
952 return CAP(uid);
953}
954
955static string PlayerWho(object obj)
956{
957 object tmp;
958 string str, stmp;
959 str=ARIGHT(""+LEVEL(obj) , 3, " ");
960 str+=ALEFT(" "+crname(obj)+" ", 12, ".");
961 str+=PlayerAge(obj);
bugfixaf2be4f2020-03-22 19:13:07 +0100962 str+=(({int})obj->QueryProp(P_GENDER)==1 ? " m " : " f ");
963 str+=(({int})obj->QueryProp(P_FROG)) ? "f" : ".";
964 str+=(({int})obj->QueryProp(P_GHOST)) ? "g" : ".";
965 str+=(({int})obj->QueryProp(P_INVIS)) ? "i" : ".";
MG Mud User88f12472016-06-24 23:31:02 +0200966 str+=(query_editing(obj)||query_input_pending(obj) ? "e" : ".");
bugfixaf2be4f2020-03-22 19:13:07 +0100967 str+=(({string})obj->QueryProp(P_AWAY)) ? "a" : ".";
MG Mud User88f12472016-06-24 23:31:02 +0200968 str+=" "+PlayerIdle(obj)+" ";
969 str+=(tmp=ENV(obj)) ? ObjFile(tmp) : "- fabric of space -";
970 return str;
971}
972
973static string PlayerMail(object obj, int flag)
974{
975 string pre;
976
977 pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
bugfixaf2be4f2020-03-22 19:13:07 +0100978 return pre+"mail: "+({string})obj->QueryProp(P_MAILADDR);
MG Mud User88f12472016-06-24 23:31:02 +0200979}
980
981static string PlayerIP(object obj, int flag)
982{
983 string pre;
984
985 pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
986 return pre+"host: "+query_ip_name(obj)+" ("+query_ip_number(obj)+")";
987}
988
989static string PlayerRace(object obj, int flag)
990{
991 string tmp, pre;
992
993 pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
bugfixaf2be4f2020-03-22 19:13:07 +0100994 pre=pre+"race: "+ALEFT(({string})obj->QueryProp(P_RACE)+" ", 10, ".")+
995 " guild: ";
996 tmp=({string})obj->QueryProp(P_GUILD);
MG Mud User88f12472016-06-24 23:31:02 +0200997 return tmp ? pre+tmp : pre+"- none -";
998}
999
1000static string PlayerDomain(object obj, int flag)
1001{
Zesstraee2fb382020-01-21 21:31:19 +01001002 string pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
MG Mud User88f12472016-06-24 23:31:02 +02001003 pre+="domainlord of: ";
bugfixaf2be4f2020-03-22 19:13:07 +01001004 string *domains = ({string*})master()->query_userlist(getuid(obj),
1005 USER_DOMAIN);
Zesstraee2fb382020-01-21 21:31:19 +01001006 if(sizeof(domains))
1007 pre += CountUp(domains, ", ", ", ");
MG Mud User88f12472016-06-24 23:31:02 +02001008 return pre;
1009}
1010
1011static string PlayerStats(object obj, int flag)
1012{
1013 string pre;
1014
1015 pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
bugfixaf2be4f2020-03-22 19:13:07 +01001016 pre+="hp="+ARIGHT(({int})obj->QueryProp(P_HP), 3, "0");
1017 pre+="/"+ARIGHT(({int})obj->QueryProp(P_MAX_HP), 3, "0");
1018 pre+=" sp="+ARIGHT(({int})obj->QueryProp(P_SP), 3, "0");
1019 pre+="/"+ARIGHT(({int})obj->QueryProp(P_MAX_SP), 3, "0");
1020 pre+=" food="+ARIGHT(({int})obj->QueryProp(P_FOOD), 3, "0");
1021 pre+="/"+ARIGHT(({int})obj->QueryProp(P_MAX_FOOD), 3, "0");
1022 pre+=" drink="+ARIGHT(({int})obj->QueryProp(P_DRINK), 3, "0");
1023 pre+="/"+ARIGHT(({int})obj->QueryProp(P_MAX_DRINK), 3, "0");
1024 pre+=" exps="+({int})obj->QueryProp(P_XP);
MG Mud User88f12472016-06-24 23:31:02 +02001025 return pre;
1026}
1027
1028static string PlayerSnoop(object obj, int flag)
1029{
1030 string tmp, pre;
1031 object victim;
1032
1033 pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
1034 pre=pre+"is snooped by: ";
1035 if(victim=query_snoop(obj))
1036 pre+=ARIGHT(" "+crname(victim), 12, ".");
1037 else
1038 pre+="............";
1039 return pre;
1040}
1041
1042static string PlayerCmdAvg(object obj, int flag)
1043{
1044 string pre;
1045
1046 pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
bugfixaf2be4f2020-03-22 19:13:07 +01001047 return pre+"cmdavg: "+({int})obj->_query_command_average();
MG Mud User88f12472016-06-24 23:31:02 +02001048}
1049
1050
1051/*----------------------------------------------------------------------
1052 * msg input to objects
1053 */
1054
1055static void XMsgSay(string str)
1056{
1057 if(str=="."||str=="**")
1058 {
1059 WLN("[End of message]");
1060 say("[End of message]\n");
1061 }
1062 else
1063 {
1064 say(str+"\n");
1065 input_to("XMsgSay");
1066 }
1067}
1068
1069static void XMsgTell(string str)
1070{
1071 if(str=="."||str=="**")
1072 {
1073 WLN("[End of message]");
1074 tell_object(msgto, "[End of message]\n");
1075 }
1076 else
1077 {
1078 tell_object(msgto, str+"\n");
1079 input_to("XMsgTell");
1080 }
1081}
1082
1083static void XMsgShout(string str)
1084{
1085 if(str=="."||str=="**")
1086 {
1087 WLN("[End of message]");
1088 shout("[End of message]\n");
1089 }
1090 else
1091 {
1092 shout(str+"\n");
1093 input_to("XMsgShout");
1094 }
1095}
1096
1097/*----------------------------------------------------------------------
1098 * own object moving
1099 */
1100
1101int move(mixed dest)
1102{
1103 move_object(ME, cloner?cloner:dest);
1104 return TRUE;
1105}
1106
1107/*----------------------------------------------------------------------
1108 * object id
1109 */
1110
1111int id(string str)
1112{
1113 if(!security()&&MODE(MODE_SCANCHK)&&RTP&&!IS_ARCH(RTP))
1114 WDLN(crname(RTP)+" scanned you (id) ["+query_verb()+"] "+
1115 (PREV ? ObjFile(PREV) : "[destructed object]"));
1116 return LOWER(str)==LOWER(TOOL_NAME);
1117}
1118
1119/*----------------------------------------------------------------------
1120 * short and long description
1121 */
1122
1123string short()
1124{
1125 return _query_short()+".\n";
1126}
1127
1128string _query_short()
1129{
1130 string sh; // added by Rumata
1131 if(cloner)
1132 {
1133 if((!security())&&MODE(MODE_SCANCHK)&&!IS_ARCH(RTP))
1134 WDLN(crname(RTP)+" scanned you (short) ["+query_verb()+"] "+
1135 (PREV ? ObjFile(PREV) : "[destructed object]"));
1136 if( sh=Query(P_SHORT) ) return sh; // added by Rumata
bugfixaf2be4f2020-03-22 19:13:07 +01001137 return ({string})cloner->name(WESSEN)+" "+TOOL_TITLE+" ["+
MG Mud User88f12472016-06-24 23:31:02 +02001138 ctime(time())[11..18]+"]";
1139 }
1140 return TOOL_TITLE;
1141}
1142
1143string long()
1144{
1145 return _query_long();
1146}
1147
1148string _query_long()
1149{
1150 if(cloner&&!security()&&MODE(MODE_SCANCHK)&&!IS_ARCH(RTP))
1151 {
1152 WDLN(crname(RTP)+" scanned you (long) ["+query_verb()+"] "+
1153 (PREV ? ObjFile(PREV) : "[destructed object]"));
1154 }
1155 return
1156 "This is "+TOOL_NAME+" version "+TOOL_VERSION+
1157 " (maintained by Kirk@MorgenGrauen)\n"+
1158 "Original copyright held by Hyp.\n"+
1159 "Gamedriver patchlevel: "+__VERSION__+" master object: "+__MASTER_OBJECT__+
1160 "\n\nDo 'xhelp' for more information.\n";
1161}
1162
1163string name(mixed dummy1, mixed dummy2)
1164{
1165 return _query_short();
1166}
1167
1168/*----------------------------------------------------------------------
1169 * light stuff
1170 */
1171
1172int _query_light()
1173{
1174 return xlight;
1175}
1176
1177int _set_light(int x)
1178{
1179 return xlight;
1180}
1181
1182/*----------------------------------------------------------------------
1183 * Autoloading
1184 */
1185
1186mixed *_query_autoloadobj()
1187{
1188 return AUTOLOAD_ARGS;
1189}
1190
1191void _set_autoloadobj(mixed *args)
1192{
1193 WLN(TOOL_TITLE+" ...");
1194 if(!pointerp(args))
1195 ;
1196 else if(sizeof(args)!=3)
1197 ;
1198 else if(!stringp(args[0]))
1199 ;
1200 else if(!intp(args[1]))
1201 ;
1202 else if(!intp(args[2]))
1203 ;
1204 else
1205 {
bugfixaf2be4f2020-03-22 19:13:07 +01001206 if(args[0]!=TOOL_INTERNAL)
MG Mud User88f12472016-06-24 23:31:02 +02001207 {
1208 WLN("*****************************");
1209 WLN("*** NEW EDITION ***");
1210 WLN("*** do 'xtool news' for ***");
1211 WLN("*** more information ***");
1212 WLN("*****************************");
1213 }
bugfixaf2be4f2020-03-22 19:13:07 +01001214 modi=args[1];
1215 morelines=args[2];
MG Mud User88f12472016-06-24 23:31:02 +02001216 return;
1217 }
1218 W("(bad autoload, using default)\n");
1219}
1220
1221/*----------------------------------------------------------------------
1222 * creation, updating and initialization stuff
1223 */
1224
1225void update_tool(mixed *args, object obj)
1226{
1227 SECURE1();
1228 if(!(obj&&args))
1229 return;
1230 Destruct(PREV);
1231 _set_autoloadobj(args);
1232 move(obj);
1233}
1234
1235void create()
1236{
1237 object obj;
1238
1239 if(member(object_name(),'#')<0)
1240 return;
1241 if(!cloner&&!((cloner=TP)||(cloner=ENV(ME)))&&!interactive(cloner))
1242 destruct(ME);
1243 if(!IS_LEARNER(cloner))
1244 destruct(ME);
1245 SetProp(P_NODROP,"Das waere zu gefaehrlich.\n");
1246 SetProp(P_NEVERDROP,1);
1247 SetProp(P_NOBUY,1);
1248 if(file_size(SAVE_FILE+".o")>0)
1249 {
1250 WDLN("Loading "+TOOL_TITLE+" settings");
1251 restore_object(SAVE_FILE);
1252 }
1253 if(MODE(MODE_FIRST))
1254 call_out("move",0,cloner);
Zesstra7e95e3f2019-10-19 11:15:05 +02001255 call_out("add_insert_hook",1);
MG Mud User88f12472016-06-24 23:31:02 +02001256}
1257
1258void TK(string str)
1259{
1260 if (!xtk)
1261 return;
1262 tell_object(cloner,"XTOOL: "+str+"\n");
1263}
1264
1265int Xtk(string str)
1266{
1267 xtk=!xtk;
1268 WDLN("Xtool internal tracing "+(xtk?"enabled":"disabled"));
1269 return TRUE;
1270}
1271
MG Mud User88f12472016-06-24 23:31:02 +02001272void init()
1273{
1274 object first, prev;
1275
1276 if(member(object_name(),'#')<0) return;
1277 first=first_inventory(ENV(ME));
1278 if(MODE(MODE_PROTECT)&&is_player(first)&&!IS_ARCH(first))
1279 {
1280 WDLN("WARNING: "+crname(first)+" tried to move into your inventory");
1281 tell_object(first, "You cannot move yourself into "+
1282 crname(cloner)+"'s inventory.\n");
1283 call_out("DropObj",0,first);
1284 return;
1285 }
1286 else if(MODE(MODE_FIRST)&&first!=ME)
1287 move(cloner);
1288 else actions();
1289}
1290
1291void DropObj(object obj)
1292{
1293 if(!obj||!objectp(obj))
1294 return;
bugfixaf2be4f2020-03-22 19:13:07 +01001295 ({int})obj->move(ENV(cloner),M_NOCHECK|M_NO_SHOW);
MG Mud User88f12472016-06-24 23:31:02 +02001296}
1297
1298#define ACTIONS\
1299([\
1300 "xcallouts" : "Xcallouts";0;1,\
1301 "xcall" : "Xcall";0;1,\
1302 "xcat" : "Xcat";1;1,\
1303 "xcd" : "Xcd";0;0,\
1304 "xclean" : "Xclean";0;0,\
1305 "xclone" : "Xclone";0;0,\
1306 "xuclone" : "Xuclone";0;0,\
1307 "xcmds" : "Xcmds";0;1,\
1308 "xdbg" : "Xdbg";0;0,\
1309 "xdclean" : "Xdclean";0;0,\
1310 "xddes" : "Xddes";0;0,\
1311 "xdes" : "Xdes";0;0,\
1312 "xdest" : "Xdes";0;0,\
1313 "xdlook" : "Xdlook";0;1,\
1314 "xdo" : "Xdo";0;0,\
1315 "xdupdate" : "Xdupdate";0;0,\
1316 "xecho" : "Xecho";0;0,\
1317 "xeval" : "Xeval";0;1,\
1318 "xforall" : "Xforall";0;0,\
1319 "xgoto" : "Xgoto";0;0,\
1320 "xhbeats" : "Xhbeats";0;1,\
1321 "xgrep" : "Xgrep";1;1,\
1322 "xhead" : "Xhead";1;1,\
1323 "xhelp" : "Xhelp";0;0,\
1324 "xinventory": "Xinventory";0;1,\
1325 "xids" : "Xids";0;0,\
1326 "xinfo" : "Xinfo";0;0,\
1327 "xinherit" : "Xinherit";0;1,\
1328 "xlag" : "Xlag";0;0,\
1329 "xlight" : "Xlight";0;0,\
1330 "xload" : "Xload";0;0,\
1331 "xlook" : "Xlook";0;1,\
1332 "xlpc" : "Xlpc";0;0,\
1333 "xman" : "Xman";0;0,\
1334 "xmore" : "Xmore";1;0,\
1335 "xmove" : "Xmove";0;0,\
1336 "xmsg" : "Xmsg";1;0,\
1337 "xmtp" : "Xmtp";0;0,\
1338 "xproc" : "Xproc";0;1,\
1339 "xprof" : "Xprof";0;0,\
1340 "xprops" : "Xprops";0;1,\
1341 "xquit" : "Xquit";0;0,\
1342 "xscan" : "Xscan";0;0,\
1343 "xset" : "Xset";0;0,\
1344 "xsh" : "Xsh";0;0,\
1345 "xsort" : "Xsort";1;1,\
1346 "xtail" : "Xtail";1;1,\
1347 "xtk" : "Xtk";0;0,\
1348 "xtool" : "Xtool";0;0,\
1349 "xtrace" : "Xtrace";0;0,\
1350 "xtrans" : "Xtrans";0;0,\
1351 "xupdate" : "Xupdate";0;0,\
1352 "xwc" : "Xwc";1;0,\
1353 "xwho" : "Xwho";0;1,\
1354 ])
1355
1356static string PrepareLine(string str)
1357{
1358 return str;
1359}
1360
1361static string QuoteLine(string str)
1362{
1363 string *tmp,*tmp2;
1364 int i, i2, len, len2, qd, qs;
1365
Zesstra4daab9a2019-11-06 22:38:18 +01001366 str=string_replace(str,"\\\\","\u00B0""BSHL");
1367 str=string_replace(str,"\\\"","\u00B0""DBLQ");
1368 str=string_replace(str,"\\\'","\u00B0""SGLQ");
1369 str=string_replace(str,"\\|","\u00B0""PIPE");
1370 str=string_replace(str,"||","\u00B0""OROR");
1371 str=string_replace(str,"->","\u00B0""LARR");
1372 str=string_replace(str,"\\$","\u00B0""DOLR");
MG Mud User88f12472016-06-24 23:31:02 +02001373 tmp=regexplode(str,"(\"|')");
1374 len=sizeof(tmp);
1375 qd=qs=0;
1376 for(i=0;i<len;i++)
1377 {
1378 if(i%2)
1379 {
1380 if(tmp[i]=="'")
1381 qd=(!qs?!qd:qd);
1382 else
1383 qs=(!qd?!qs:qs);
1384 if((tmp[i]=="\""&&!qd)||(tmp[i]=="'"&&!qs))
1385 tmp[i]="";
1386 }
1387 else
1388 {
1389 if(!qd)
1390 {
1391 len2=sizeof(tmp2=regexplode(tmp[i],"\\$[^ ][^ ]*"));
1392 for(i2=0;i2<len2;i2++)
1393 if(i2%2)
1394 {
1395 TK("QuoteLine: "+tmp2[i2][1..]);
1396 tmp2[i2]=(string)XFindObj((tmp2[i2])[1..]);
1397 }
1398 tmp[i]=implode(tmp2,"");
1399 }
1400 }
1401 }
1402 if(qd||qs)
1403 return NULL;
1404 str=implode(tmp,"");
1405 TK("QuoteLine: str: "+str);
1406 return str;
1407}
1408
1409static string UnquoteLine(string str)
1410{
Zesstra4daab9a2019-11-06 22:38:18 +01001411 str=string_replace(str,"\u00B0""BSHL","\\");
1412 str=string_replace(str,"\u00B0""DBLQ","\"");
1413 str=string_replace(str,"\u00B0""SGLQ","\'");
1414 str=string_replace(str,"\u00B0""DQUO","");
1415 str=string_replace(str,"\u00B0""SQUO","");
1416 str=string_replace(str,"\u00B0""PIPE","|");
1417 str=string_replace(str,"\u00B0""OROR","||");
1418 str=string_replace(str,"\u00B0""LARR","->");
1419 str=string_replace(str,"\u00B0""DOLR","$");
MG Mud User88f12472016-06-24 23:31:02 +02001420 TK("UnquoteLine: str: "+str);
1421 return str;
1422}
1423
1424static string *ExplodeCmds(string str)
1425{
1426 string *tmp;
1427
1428 tmp=regexplode(str,"\\||>|>>");
1429 while(tmp[<1]=="")
1430 tmp=tmp[0..<2];
1431 return tmp;
1432}
1433
1434varargs int ParseLine(string str)
1435{
1436 string verb, arg;
1437 int ret;
1438
1439 TK("ParseLine: str: "+(str?str:""));
1440 if(!sizeof(cmds))
1441 {
1442 // this is a single command or beginning of a command pipe
1443 verb=query_verb();
1444
1445 // return on unknown commands
1446 if(!verb||!sizeof(verb)||!GetFunc(verb,TRUE))
1447 return FALSE;
1448
bugfixaf2be4f2020-03-22 19:13:07 +01001449 str=({string})this_player()->_unparsed_args();
MG Mud User88f12472016-06-24 23:31:02 +02001450 pipe_in=FALSE;
1451 pipe_of=NULL;
1452 pipe_ovr=TRUE;
1453 pipe_out=FALSE;
1454 pipe_of=NULL;
1455 // pass arguments to some special functions unparsed
1456 if(member(({"xlpc","xcall","xeval"}),verb)>=0)
1457 {
1458#ifdef XDBG
1459 TK("ParseLine: special func: "+verb);
1460#endif
1461 ret=CallFunc(verb,str);
1462 SafeReturn(ret);
1463 }
1464 // ok, here we go
1465 pipe_in=pipe_out=FALSE;
1466 pipe_if=pipe_of=NULL;
1467 pipe_ovr=TRUE;
1468 if(file_size(PIPE_FILE)>=0)
1469 rm(PIPE_FILE);
1470 if (str&&str!="")
1471 {
1472 if(!(str=QuoteLine(str)))
1473 {
1474 WDLN("Unterminated quotation");
1475 SafeReturn(TRUE);
1476 }
1477 cmds=ExplodeCmds(str);
1478 }
1479 else
1480 cmds=({""});
1481 arg=strip_string(cmds[0]);
1482 }
1483 else
1484 {
1485 cmds[0]=strip_string(cmds[0]);
1486 TK("ParseLine: cmds[0]: "+cmds[0]);
1487 if(sscanf(cmds[0],"%s %s",verb,arg)!=2)
1488 {
1489 verb=cmds[0];
1490 arg="";
1491 }
1492 }
1493 cmds=cmds[1..];
1494 TK("ParseLine: verb: "+verb);
1495 if (!verb||!sizeof(verb)||!GetFunc(verb,TRUE))
1496 SafeReturn(FALSE);
1497 TK("ParseLine(1): arg: "+arg+" cmds: "+sprintf("%O",cmds));
1498 switch(sizeof(cmds))
1499 {
1500 case 0:
1501 ret=CallFunc(verb,strip_string(UnquoteLine(arg)));
1502 SafeReturn(ret);
1503 break;
1504
1505 case 1:
1506 WDLN("Missing rhs of command pipe");
1507 SafeReturn(TRUE);
1508 break;
1509
1510 default:
1511 pipe_out=TRUE;
1512 switch(cmds[0])
1513 {
1514 case "|":
1515 pipe_of=PIPE_FILE;
1516 pipe_ovr=TRUE;
1517 cmds=cmds[1..];
1518 break;
1519
1520 case ">":
1521 pipe_ovr=TRUE;
1522 if(sizeof(cmds)!=2)
1523 {
1524 WDLN("Illegal IO redirection");
1525 SafeReturn(TRUE);
1526 }
1527 pipe_of=cmds[1];
1528 cmds=({});
1529 break;
1530
1531 case ">>":
1532 pipe_ovr=FALSE;
1533 if(sizeof(cmds)!=2)
1534 {
1535 WDLN("Illegal IO redirection");
1536 SafeReturn(TRUE);
1537 }
1538 pipe_of=cmds[1];
1539 cmds=({});
1540 break;
1541 }
1542 }
1543 TK("ParseLine(2): arg: "+arg+" cmds: "+sprintf("%O",cmds));
1544 if(!CallFunc(verb,strip_string(arg)))
1545 SafeReturn(FALSE);
1546 pipe_in=pipe_out;
1547 pipe_if=pipe_of;
1548 pipe_ovr=FALSE;
1549 pipe_out=FALSE;
1550 pipe_of=NULL;
1551 if(sizeof(cmds))
1552 call_out("ParseLine",0);
1553 else
1554 SafeReturn(TRUE);
1555 return TRUE;
1556}
1557
1558static int CallFunc(string verb, string str)
1559{
1560 string fun;
1561
1562 fun=GetFunc(verb,FALSE);
1563#ifdef XDBG
1564 TK("CallFunc: verb: "+verb+" str: "+str);
1565 TK("CallFunc: resolved function: "+(fun?fun:"(unresolved)"));
1566#endif
1567 if(str=="")
1568 str=NULL;
bugfixaf2be4f2020-03-22 19:13:07 +01001569 return fun?({int})call_other(ME,fun,str):FALSE;
MG Mud User88f12472016-06-24 23:31:02 +02001570}
1571
1572static string GetFunc(string verb, int test)
1573{
1574 string fun,*keys,key;
1575 int i,len;
1576
1577 TK("GetFunc: verb: "+verb);
1578
1579 if(verb[0..0]!="x") // Assume all commands start with "x"
1580 return 0;
1581
bugfixaf2be4f2020-03-22 19:13:07 +01001582 if (!(fun=ACTIONS[verb,0])) { // Try exact hit first
MG Mud User88f12472016-06-24 23:31:02 +02001583 key="";
1584 len=sizeof(verb);
1585 for (i=sizeof(keys=m_indices(ACTIONS))-1;i>=0;i--) {
1586 TK(" trying: "+keys[i]);
1587 if(sizeof(keys[i])>=len&&keys[i][0..len-1]==verb) {
1588 if(sizeof(key)) {
1589 WLN("Das ist nicht eindeutig ...");
1590 return 0;
1591 }
1592 fun=ACTIONS[keys[i],0];
1593 key=keys[i];
1594 //break;
1595 }
1596 }
1597 } else
1598 key=verb;
1599
1600 if(test)
1601 return fun;
1602
1603 if (key) {
1604#ifdef XDBG
1605 TK("GetFunc: fun: "+fun+" (key: "+key+")\n"+
1606 "pipe_in: "+(pipe_in?"TRUE ":"FALSE ")+(pipe_if?pipe_if:"(NULL)")+"\n"+
1607 "pipe_out: "+(pipe_out?"TRUE ":"FALSE ")+(pipe_of?pipe_of:"(NULL)")+"\n"+
1608 "pipe_ovr: "+(pipe_ovr?"TRUE":"FALSE"));
1609#endif
1610 if (pipe_in&&!ACTIONS[key,PIPE_IN])
1611 {
1612 // this command does not read pipes
1613#ifdef XDBG
1614 TK("Illegal rhs of command pipe \""+fun+"\"\n");
1615#endif
1616 notify_fail("Illegal rhs of command pipe \""+fun+"\"\n");
1617 return 0;
1618 }
1619 else if (pipe_out&&!ACTIONS[key,PIPE_OUT])
1620 {
1621 // this command does not feed pipes
1622#ifdef XDBG
1623 TK("Illegal lhs of command pipe \""+fun+"\"\n");
1624#endif
1625 notify_fail("Illegal lhs of command pipe \""+fun+"\"\n");
1626 return 0;
1627 }
1628 }
1629 return fun;
1630}
1631
1632void actions()
1633{
1634 if (!cloner||!RTP||cloner==RTP||query_wiz_level(cloner)<=query_wiz_level(RTP))
1635 add_action("ParseLine","",1);
1636 add_action("CommandScan", "", 1);
1637}
1638
1639/*----------------------------------------------------------------------
1640 * the checking stuff
1641 */
1642
Zesstra7e95e3f2019-10-19 11:15:05 +02001643public <int|object>* insert_hook(object pl, int hookid, object ob)
MG Mud User88f12472016-06-24 23:31:02 +02001644{
Zesstra7e95e3f2019-10-19 11:15:05 +02001645 if(cloner && cloner == pl && hookid == H_HOOK_INSERT)
1646 {
1647 if(MODE(MODE_FIRST) && find_call_out("move")==-1)
1648 call_out("move",0,cloner);
1649 if(MODE(MODE_INVCHECK))
1650 write_newinvobj(ob);
1651 }
1652 return ({H_NO_MOD, ob});
1653}
1654
1655void add_insert_hook()
1656{
1657 if(objectp(cloner))
bugfixaf2be4f2020-03-22 19:13:07 +01001658 ({int})cloner->HRegisterToHook(H_HOOK_INSERT, #'insert_hook,
Zesstra7e95e3f2019-10-19 11:15:05 +02001659 H_HOOK_LIBPRIO(2), H_LISTENER, 0);
MG Mud User88f12472016-06-24 23:31:02 +02001660}
1661
1662static void VarCheck(int show)
1663{
1664 int i, s;
1665 foreach(string k, mixed v : variable)
1666 {
1667 if (v) continue;
1668 if(show) WDLN("*** Variable $"+k+" has been destructed");
1669 m_delete(variable, k);
1670 }
1671}
1672
1673
1674int write_newinvobj(object obj)
1675{
1676 if(obj) WDLN("*** New object in inventory "+ObjFile(obj));
1677 return(1);
1678}
1679
1680/*----------------------------------------------------------------------
1681 * catch all commands, absorb forces and check history
1682 */
1683
1684int CommandScan(string arg)
1685{
1686 string verb, cmd;
1687 object rtp;
1688 rtp=RTP;
1689
1690 if(!cloner&&!(cloner=rtp)) destruct(ME);
1691
1692 if((!MODE(MODE_PROTECT))||security()||
1693 query_wiz_level(cloner)<query_wiz_level(rtp))
1694 {
1695 verb=query_verb();
1696 if(verb&&DoHistory(verb+(arg ? " "+arg : "")))
1697 return TRUE;
1698 nostore=FALSE;
1699 return FALSE;
1700 }
1701 else
1702 {
1703 if(rtp)
1704 {
1705 WDLN("Your "+TOOL_TITLE+" protects you from a force by "+crname(rtp)+
1706 " ["+query_verb()+(arg ? " "+arg+"]" : "]"));
1707 tell_object(rtp, crname(cloner)+"'s "+TOOL_TITLE+
1708 " absorbes your force.\n");
1709 }
1710 else
1711 {
1712 WDLN("Your "+TOOL_TITLE+" protects you from a force ["+
1713 query_verb()+(arg ? " "+arg+"]" : "]"));
1714 }
1715 return TRUE;
1716 }
1717}
1718
1719int DoHistory(string line)
1720{
1721 int i;
1722 string cmd, *strs;
1723
1724 SECURE2(FALSE);
1725 if(!stringp(line) || !sizeof(line))
1726 return TRUE;
1727 else if(line=="%!")
1728 {
1729 WLN("Current command history:");
1730 for(i=MAX_HISTORY; i; --i)
1731 if(history[i-1])
1732 {
1733 W(" "+ARIGHT(""+i, 2, " ")+": ");
1734 if(sizeof(history[i-1])>70)
1735 WLN(ALEFT(history[i-1], 70, " "));
1736 else
1737 WLN(history[i-1]);
1738 }
1739 return TRUE;
1740 }
1741 else if(line[0..1]=="%%" && (cmd=history[0]+line[2..<1]))
1742 {
1743 Command(cmd);
1744 return TRUE;
1745 }
1746 else if(line[0]=='^'&&(strs=strip_explode(line, "^")))
1747 {
1748 if(sizeof(strs)&&strs[0]&&(cmd=history[0]))
1749 {
1750 if(sizeof(strs)==2)
1751 cmd=string_replace(cmd, strs[0], strs[1]);
1752 else
1753 cmd=string_replace(cmd, strs[0], "");
1754 nostore--;
1755 Command(cmd);
1756 nostore++;
1757 return TRUE;
1758 }
1759 }
1760 else if(line[0]=='%' && (sscanf(line[1..<1], "%d", i)))
1761 {
1762 i= i>0 ? i : 1;
1763 i= i<=MAX_HISTORY ? i : MAX_HISTORY;
1764 if(cmd=history[i-1])
1765 Command(cmd);
1766 return TRUE;
1767 }
1768 else if(line[0]=='%')
1769 {
1770 for(i=0; i<MAX_HISTORY; i++)
1771 {
1772 if(history[i]&&
1773 history[i][0..sizeof(line)-2]==line[1.. <1])
1774 {
1775 Command(history[i]);
1776 return TRUE;
1777 }
1778 }
1779 }
1780 else if(nostore<1)
1781 history=({line})+history[0..MAX_HISTORY-2];
1782 return FALSE;
1783}
1784