blob: beeab8fc14efa216913ab1ec4167620ffac89e38 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// fileview.c
4//
5// $Id: fileview.c 9142 2015-02-04 22:17:29Z Zesstra $
Zesstraefad7be2018-11-06 23:18:30 +01006#pragma strict_types, rtt_checks
Zesstra0d64cca2020-03-09 21:03:56 +01007#pragma range_check
MG Mud User88f12472016-06-24 23:31:02 +02008#pragma no_clone
MG Mud User88f12472016-06-24 23:31:02 +02009
10#include <ansi.h>
11#include <player/base.h>
12#include <wizlevels.h>
13#include <shells.h>
14#include <daemon/mand.h>
15#include <udp.h>
Zesstraefad7be2018-11-06 23:18:30 +010016#include <files.h>
Zesstrac70bf582019-11-26 00:43:17 +010017#include <rtlimits.h>
Zesstraefad7be2018-11-06 23:18:30 +010018
MG Mud User88f12472016-06-24 23:31:02 +020019#define NEED_PROTOTYPES
20#include <magier.h>
21#include <thing/properties.h>
22#include <player.h>
23
24private nosave mapping colorstrings;
25private nosave mapping oldman_result;
26
27// ###################
28//######################### INITIALISIERUNG #############################
29// ###################
30
31mixed _query_localcmds()
32{
33 return ({({"ls","_ls",0,LEARNER_LVL}),
34 ({"more","_more",0,LEARNER_LVL}),
35 ({"cat","_cat",0,LEARNER_LVL}),
36 ({"head","_cat",0,LEARNER_LVL}),
37 ({"tail","_cat",0,LEARNER_LVL}),
38 ({"man","_man",0,LEARNER_LVL}),
39 ({"rman","_rman",0,LEARNER_LVL}),
40 ({"showprops","_showprops",0,WIZARD_LVL}),
41 ({"grep","_grep",0,LEARNER_LVL})});
42}
43
44
45// ######
46//################################ LS ###################################
47// ######
48
49//
50// _ls: Der ls-Befehl: Verzeichnisse und Dateien anzeigen
51// cmdline: Kommandozeile
52//
53
54//
55// Funktionen zum Sortieren und fuer filter_ldfied/map_ldfied
56//
57
58
59private string _get_color(string color)
60{
61 return COLORS[lower_case(color)];
62}
63
64
65private void SetColorstrings()
66{
67 string tmp,term;
68 mapping vars;
69 vars=QueryProp(P_VARIABLES);
70 colorstrings=m_allocate(0,2);
71 switch(term=QueryProp(P_TTY))
72 {
73 case "vt100":
74 case "ansi":
75 if(stringp(vars["LS_DIR"]))
76 tmp=implode(map(explode(vars["LS_DIR"],"+"),#'_get_color),
77 "");
78 else
79 tmp = (term == "ansi") ? ANSI_BLUE+ANSI_BOLD: ANSI_BOLD;
80 colorstrings[DIR] = tmp+"%s"+(term == "vt100"?"/":"")+ANSI_NORMAL;
81 if(term == "vt100") colorstrings[DIR, 1] = 1;
82 if(stringp(vars["LS_OBJ"]))
83 tmp=implode(map(explode(vars["LS_OBJ"],"+"),#'_get_color),
84 "");
85 else
86 tmp = (term == "ansi") ? ANSI_RED : ANSI_INVERS;
87 colorstrings[OBJ] = tmp+"%s"+ANSI_NORMAL;
88 if(stringp(vars["LS_VC"]))
89 tmp=implode(map(explode(vars["LS_VC"],"+"),#'_get_color),
90 "");
91 else
92 tmp = (term == "ansi") ? ANSI_PURPLE : ANSI_INVERS;
93 colorstrings[VC] = tmp+"%s"+ANSI_NORMAL;
94 break;
95 case "dumb":
96 colorstrings[DIR] = "%s/"; colorstrings[DIR, 1] = 1;
97 colorstrings[OBJ] = "%s*"; colorstrings[OBJ, 1] = 1;
98 colorstrings[VC] = "%s*"; colorstrings[VC , 1] = 1;
99 break;
100 default:
101 colorstrings[DIR] = "%s";
102 colorstrings[OBJ] = "%s";
103 colorstrings[VC] = "%s";
104 }
105 return;
106}
107
108
109private string _ls_output_short(mixed filedata,
110 int maxlen,int counter,int maxcount)
111{
112 string tmp;
113 tmp=filedata[BASENAME];
114 maxlen-=sizeof(tmp);
115 switch(filedata[FILESIZE])
116 {
Zesstraefad7be2018-11-06 23:18:30 +0100117 case FSIZE_DIR: tmp=sprintf(colorstrings[DIR],tmp);
MG Mud User88f12472016-06-24 23:31:02 +0200118 maxlen-=colorstrings[DIR,1]; break;
Zesstraefad7be2018-11-06 23:18:30 +0100119 case FSIZE_NOFILE: tmp=sprintf(colorstrings[VC],tmp);
MG Mud User88f12472016-06-24 23:31:02 +0200120 maxlen-=colorstrings[VC,1]; break;
121 default: if (find_object(filedata[FULLNAME]))
122 {
123 maxlen-=colorstrings[OBJ,1];
124 tmp=sprintf(colorstrings[OBJ],tmp); break;
125 }
126 }
127 if (!maxcount) return tmp+"\n";
128 return sprintf("%-*s%s",(maxlen+sizeof(tmp)),tmp,
Zesstraefad7be2018-11-06 23:18:30 +0100129 ((counter++)==maxcount?(counter=0,"\n"):" "));
MG Mud User88f12472016-06-24 23:31:02 +0200130}
131
132private int _ls_maxlen(mixed filedata,int flags,int maxlen)
133{
134 string base;
135 int size;
136 base=filedata[BASENAME];
137 if (!(flags&LS_A)&&(base[0]=='.')) return 0;
MG Mud User88f12472016-06-24 23:31:02 +0200138 maxlen=max(maxlen,sizeof(base));
MG Mud User88f12472016-06-24 23:31:02 +0200139 return 1;
140}
141
142private string _ls_output_long(mixed filedata, int flags,closure valid_read,
143 closure valid_write,closure creator_file)
144{
Zesstraefad7be2018-11-06 23:18:30 +0100145 string base=filedata[BASENAME];
146 if (!(sizeof(base)) || ( (!(flags&LS_A)) && (base[0]=='.')) )
MG Mud User88f12472016-06-24 23:31:02 +0200147 return 0;
Zesstraefad7be2018-11-06 23:18:30 +0100148 int size=filedata[FILESIZE];
149 string path=filedata[PATHNAME];
Zesstraf22b6a82018-11-07 22:39:55 +0100150 string full=filedata[FULLNAME];
Zesstraefad7be2018-11-06 23:18:30 +0100151 int dir=(size==FSIZE_DIR);
152 object ob=find_object(full);
153 int ftime=filedata[FILEDATE];
154 string date;
Bugfix59cb0e52019-09-06 15:17:29 +0200155 if ((time()-ftime)>31536000) // ein Jahr
Zesstraefad7be2018-11-06 23:18:30 +0100156 date=strftime("%b %e %Y", ftime);
157 else
158 date=strftime("%b %e %H:%M", ftime);
159
160 string creator="";
161 string group="";
MG Mud User88f12472016-06-24 23:31:02 +0200162 if (flags&LS_U)
163 {
Vanion50652322020-03-10 21:13:25 +0100164 creator=({string})call_other(master(),"creator_file", full);
MG Mud User88f12472016-06-24 23:31:02 +0200165 switch(creator)
166 {
167 case ROOTID: creator="root"; break;
Zesstraefad7be2018-11-06 23:18:30 +0100168 case BACKBONEID: creator="std"; break;
169 case MAILID: creator="mail"; break;
170 case NEWSID: creator="news"; break;
171 case NOBODY: creator="nobody"; break;
172 case POLIZEIID: creator="polizei"; break;
173 case DOCID: creator="doc"; break;
174 case GUILDID: creator="gilde"; break;
175 case ITEMID: creator="items"; break;
MG Mud User88f12472016-06-24 23:31:02 +0200176 default: if(!creator) creator="none"; break;
177 }
178 }
179 if (flags&LS_G)
180 {
Zesstraf22b6a82018-11-07 22:39:55 +0100181 string *tmp=explode(path, "/") - ({""});
MG Mud User88f12472016-06-24 23:31:02 +0200182 if (sizeof(tmp))
183 {
184 switch(tmp[0])
185 {
186 case WIZARDDIR: group="magier"; break;
Zesstraefad7be2018-11-06 23:18:30 +0100187 case NEWSDIR: group="news"; break;
188 case MAILDIR: group="mail"; break;
189 case FTPDIR: group="public"; break;
190 case PROJECTDIR: group="project"; break;
MG Mud User88f12472016-06-24 23:31:02 +0200191 case DOMAINDIR: if (sizeof(tmp)>1) { group=tmp[1]; break; }
192 default: group="mud"; break;
193 }
194 }
195 else group="mud";
196 }
197 if (dir) base=sprintf(colorstrings[DIR],base);
198 else
199 {
200 if (ob)
201 {
Zesstraefad7be2018-11-06 23:18:30 +0100202 if (size==FSIZE_NOFILE)
MG Mud User88f12472016-06-24 23:31:02 +0200203 base=sprintf(colorstrings[VC],base);
204 else
205 base=sprintf(colorstrings[OBJ],base);
206 }
207 }
Zesstraefad7be2018-11-06 23:18:30 +0100208 return sprintf(("%c%c%c%c %3d" + ((flags&LS_U) ? " %-24.24s" : "%-0.1s")
209 +((flags&LS_G) ? " %-8.8s" : "%0.1s") + " %8s %s %s\n"),
210 (dir ? 'd' : '-'),
MG Mud User88f12472016-06-24 23:31:02 +0200211 (!funcall(valid_read,full,getuid(),
Zesstraefad7be2018-11-06 23:18:30 +0100212 "read_file",this_object()) ? '-' : 'r'),
MG Mud User88f12472016-06-24 23:31:02 +0200213 (!funcall(valid_write,full,getuid(),
Zesstraefad7be2018-11-06 23:18:30 +0100214 "write_file",this_object()) ? '-' : 'w'),
215 (ob ? 'x' : '-'),
216 (dir ? (sizeof((get_dir(full+"/*")||({}))-({".",".."}))) : 0),
217 creator, group,
218 (dir ? "-" : size==FSIZE_NOFILE ? "<vc>" : to_string(size)),
219 date, base);
MG Mud User88f12472016-06-24 23:31:02 +0200220}
221
222
223static int _ls(string cmdline)
224{
225 int flags,cmp,i,arg_size,size;
226 int maxlen,counter,maxcount;
Arathorna8ae8662019-11-25 19:01:19 +0100227 mixed* args;
228 string output;
MG Mud User88f12472016-06-24 23:31:02 +0200229 mixed *tmp;
230 closure output_fun,v_read,v_write,creator,sort_fun;
231
232 cmdline=_unparsed_args()||"";
233 args=parseargs(cmdline,&flags,LS_OPTS,1);
234 if (flags==-1)
235 return USAGE("ls [-" LS_OPTS "] [<Verzeichnis>] [<Verzeichnis2> ..]");
236 SetColorstrings();
237 output="";
238 if (!sizeof(args)) args=({ QueryProp(P_CURRENTDIR) });
239 if (!sizeof(args=file_list(args,MODE_LSA,0,"/")))
240 return notify_fail("ls: Keine passenden Verzeichnisse gefunden.\n"), 0;
241// Files sortieren die erste
242 if (flags&LS_T) cmp=FILEDATE;
243 else if (flags&LS_S) cmp=FILESIZE;
244 else cmp=BASENAME; // =0 :-)
Arathorn06b52922018-11-26 20:47:10 +0100245
246 if ( !cmp && !(flags&LS_R) || cmp && (flags&LS_R) )
247 sort_fun = function int (mixed* a, mixed* b) {
248 return (a[cmp] > b[cmp]);
249 };
250 else
251 sort_fun = function int (mixed* a, mixed* b) {
252 return (a[cmp] < b[cmp]);
253 };
MG Mud User88f12472016-06-24 23:31:02 +0200254 args=sort_array(args,sort_fun);
255// Ausgabeformat bestimmen
256 if (flags&LS_L)
257 {
258 v_read=VALID_READ_CL;
259 v_write=VALID_WRITE_CL;
260 creator=CREATOR_CL;
261 }
262 arg_size=sizeof(args);
263 if (arg_size>1||(arg_size&&args[0][FILESIZE]>=0))
264 {
265 if (flags&LS_L)
266 tmp=map(args,#'_ls_output_long,flags,v_read,
267 v_write,creator)-({0});
268 else
269 {
270 counter=0;maxlen=0;
271 tmp=filter(args,#'_ls_maxlen,flags,&maxlen);
272 if (maxlen>76) maxlen=76;
273 maxcount=(78/(maxlen+2))-1;
274 tmp=map(tmp,#'_ls_output_short,maxlen,&counter,maxcount);
275 }
276 output=sprintf("\n%d Dateien/Unterverzeichnisse:\n%s\n",
277 sizeof(tmp),implode(tmp,""));
278 }
279 for(i=0;i<arg_size;i++)
280 {
281 tmp=({});
282 size=args[i][FILESIZE];
Zesstraefad7be2018-11-06 23:18:30 +0100283 if (size==FSIZE_DIR)
MG Mud User88f12472016-06-24 23:31:02 +0200284 {
285 tmp=file_list(({args[i][FULLNAME]+"/*"}),MODE_LSB,0,"/");
286 tmp=sort_array(tmp,sort_fun);
287 if (flags&LS_L)
288 tmp=map(tmp,#'_ls_output_long,flags,v_read,
289 v_write,creator)-({0});
290 else
291 {
292 counter=0;maxlen=0;
293 tmp=filter(tmp,#'_ls_maxlen,flags,&maxlen);
294 maxcount=(78/(maxlen+2));
295 if (maxcount) maxcount--;
296 tmp=map(tmp,#'_ls_output_short,maxlen,&counter,maxcount);
297 }
298 if (sizeof(tmp))
299 {
300 output+=sprintf("\n%s: Verzeichnis, %d Dateien/Unterverzeichnisse:\n",
301 args[i][FULLNAME],sizeof(tmp));
302 output+=(implode(tmp,"")+((string)(tmp[<1][<1..<1])=="\n"?"":"\n"));
303 }
304 else
305 {
306 output+=sprintf("\n%s: Leeres Verzeichnis.\n",args[i][FULLNAME]);
307 }
308 }
309 }
310 More(output);
311 return 1;
312}
313
314// ########
315//############################### MORE ###################################
316// ########
317//
318// _more_file: Mehrere Files hintereinander ausgeben
319//
320
321private void _more_file(string *arg)
322{
323 if (!sizeof(arg)) return;
324 printf("more: Naechste Datei: %s\n",arg[0]);
Zesstra3de3a032018-11-08 19:17:03 +0100325 More(arg[0],1,#'_more_file,
326 (sizeof(arg)>1 ? ({ arg[1..]}) : ({})) );
MG Mud User88f12472016-06-24 23:31:02 +0200327 return;
328}
329
330
331private mixed _size_filter(mixed *arg)
332{
333 if (arg[FILESIZE]>0) return arg[FULLNAME];
334 if (arg[FILESIZE]==0)
335 {
336 printf("%s: %s: Leere Datei.\n",query_verb()||"more",arg[FULLNAME]);
337 return 0;
338 }
Zesstraefad7be2018-11-06 23:18:30 +0100339 if (arg[FILESIZE]==FSIZE_DIR)
MG Mud User88f12472016-06-24 23:31:02 +0200340 printf("%s: %s ist ein Verzeichnis.\n",query_verb()||"more",arg[FULLNAME]);
341 else
342 printf("%s: %s: Datei existiert nicht.\n", query_verb()||"more",
343 arg[FULLNAME]);
344 return 0;
345}
346
347
348//
349// _more: Dateien anzeigen
350// cmdline: Kommandozeile
351//
352
353static int _more(string cmdline)
354{
355 mixed *args;
356 int flags;
357 cmdline=_unparsed_args();
358 args=parseargs(cmdline,&flags,"",1);
359 if (flags==-1||!sizeof(args)) return USAGE("more <datei> [<datei2>..]");
360 args=file_list(args,MODE_MORE,0,"/");
361 if (!sizeof(args))
362 return printf("more: %s: Keine passende Datei gefunden.\n",cmdline),1;
363 args=map(args,#'_size_filter)-({0});
364 if (sizeof(args)) _more_file(args);
365 return 1;
366}
367
368// ###################
369//########################## HEAD, TAIL, CAT #############################
370// ###################
371
372static int _cat(string cmdline)
373{
374 mixed *args;
375 int flags;
376 cmdline=_unparsed_args();
377 args=parseargs(cmdline,&flags,"",1);
378 if(flags==-1||!sizeof(args))
379 return USAGE(query_verb()+" <dateiname> [<datei2>..]");
380 args=file_list(args,MODE_CAT,0,"/");
381 if (!sizeof(args))
382 return printf("%s: %s: Keine passende Datei gefunden.\n",query_verb(),
383 cmdline),1;
384 args=map(args,#'_size_filter)-({0});
385 if (!sizeof(args)) return 1;
386 while(sizeof(args))
387 {
388 switch(query_verb())
389 {
390 case "cat":
391 if (!cat(args[0]))
392 printf("cat: %s konnte nicht angezeigt werden.\n",args[0]);
393 break;
394 case "head":
395 if (!cat(args[0],0,10))
396 printf("head: %s konnte nicht angezeigt werden.\n",args[0]);
397 break;
398 case "tail": tail(args[0]); break;
399 }
Zesstra3de3a032018-11-08 19:17:03 +0100400 if (sizeof(args) > 1)
401 args=args[1..];
402 else
403 break;
MG Mud User88f12472016-06-24 23:31:02 +0200404 }
405 return 1;
406}
407
408// #######
409//############################### MAN ###################################
410// #######
411
Arathorn99c40582020-08-28 19:46:23 +0200412/* Sortiert ein Array paarweise, wobei von jedem Wertepaar der erste Wert
413 fuer die Sortierung herangezogen wird. */
414private string* SortInPairs(string* arr) {
415 if (!sizeof(arr))
416 return arr;
417
418 string** helper = ({});
419
420 /* In Sub-Arrays zerlegen, die jeweils ein Wertepaart enthalten:
421 ({s0, s1, s2, s3}) => ({({s0,s1}), ({s2,s3})}) */
422 int listsize = sizeof(arr);
423 for(int i ; i<listsize ; i+=2) {
424 helper += ({ arr[i..i+1] });
425 }
426
427 // Nach dem ersten Element jedes Sub-Arrays sortieren.
428 helper = sort_array(helper, function int (string* h1, string* h2) {
429 return lower_case(h1[0]) > lower_case(h2[0]);
430 });
431
432 // Eingabe-Array loeschen und aus den sortierten Wertepaaren neu aufbauen.
433 arr = ({});
434 foreach(string* h : helper) {
435 arr += h;
436 }
437
438 return arr;
439}
440
MG Mud User88f12472016-06-24 23:31:02 +0200441static int _man(string cmdline)
442{
MG Mud User88f12472016-06-24 23:31:02 +0200443 int i, flags;
Arathorndb201cc2020-08-28 17:02:38 +0200444 string *input;
MG Mud User88f12472016-06-24 23:31:02 +0200445
Arathorn1facd5f2020-08-28 16:41:17 +0200446 string* args = parseargs(_unparsed_args(), &flags, MAN_OPTS, 0);
447
MG Mud User88f12472016-06-24 23:31:02 +0200448 if (flags==-1 ||
449 (sizeof(args)!=1 &&
450 (sizeof(args)<2 || sizeof(args[1])>1 || !(i=to_int(args[1])))))
451 return USAGE("man [-" MAN_OPTS "] <hilfeseite>");
MG Mud User88f12472016-06-24 23:31:02 +0200452
Arathorn72c7e542020-08-28 16:50:28 +0200453 input = explode(args[0], "/");
454
Arathorn815f2742020-08-28 17:29:04 +0200455 /* Wenn das Ergebnis einer vorherigen Suche noch vorliegt und die aktuelle
456 Eingabe als einziges eine einstellige Zahl enthaelt, und diese dann in
457 dem alten Suchergebnis enthalten ist, wird die Eingabe durch das alte
458 Ergebnis ersetzt. <i> wird in dem Fall geloescht.
459 Wenn kein altes Ergebnis gefunden wurde, enthaelt <i> die eingegebene
460 Nummer. */
Arathorn72c7e542020-08-28 16:50:28 +0200461 if (oldman_result && sizeof(input)==1 && sizeof(args)==1 &&
462 sizeof(input[0])==1 && (i=to_int(input[0])) &&
Arathornd0a1e662020-08-28 17:01:24 +0200463 member(oldman_result,i))
464 {
Arathorn72c7e542020-08-28 16:50:28 +0200465 input = ({oldman_result[i,0], oldman_result[i,1]});
Arathornd0a1e662020-08-28 17:01:24 +0200466 i = 0;
MG Mud User88f12472016-06-24 23:31:02 +0200467 }
Arathorn815f2742020-08-28 17:29:04 +0200468 /* Ansonsten wenn weder -m, noch -r gesetzt sind und es eine Manpage gibt,
469 die genau der Eingabe entspricht, wird diese verwendet. */
Arathorn72c7e542020-08-28 16:50:28 +0200470 else if (!(flags&(MAN_M|MAN_R)) && sizeof(input)>1)
MG Mud User88f12472016-06-24 23:31:02 +0200471 {
Arathornd0a1e662020-08-28 17:01:24 +0200472 if (file_size(MAND_DOCDIR+args[0]) >= 0)
Arathorn72c7e542020-08-28 16:50:28 +0200473 input = ({input[<1], args[0]});
MG Mud User88f12472016-06-24 23:31:02 +0200474 else
Arathorn72c7e542020-08-28 16:50:28 +0200475 input = ({});
MG Mud User88f12472016-06-24 23:31:02 +0200476 }
477 else
478 {
Arathorn815f2742020-08-28 17:29:04 +0200479 /* Soll eine Regexp-Suche durchgefuehrt werden? Dann erstmal den Ausdruck
480 auf Gueltigkeit pruefen. */
MG Mud User88f12472016-06-24 23:31:02 +0200481 if (flags&MAN_R)
482 {
Arathornd0a1e662020-08-28 17:01:24 +0200483 flags &= (~MAN_M);
484 if (catch(regexp(({""}), args[0])) || !regexp(({""}), args[0]))
485 {
486 printf("man: Ungueltiger Ausdruck in Maske.\n");
487 return 1;
488 }
MG Mud User88f12472016-06-24 23:31:02 +0200489 }
Arathorn815f2742020-08-28 17:29:04 +0200490 /* Die Ausgabe von locate() liefert ein String-Array, das abwechselnd den
491 Dateinamen der gefundenen Manpage und den vollen Pfad dieser Manpage
492 unterhalb von /doc enthaelt. Beispielsweise ({"Defend","lfun/Defend"})
493 */
Arathorn72c7e542020-08-28 16:50:28 +0200494 input = ({string *})MAND->locate(args[0], flags&(MAN_M|MAN_R));
Arathorn84dd5f22020-08-28 17:24:44 +0200495 // Sortierung case-insensitive, ggf. vorhandene Pfade dabei ignorieren
496 // Wird fuer die spaetere Ausgabe der Liste benoetigt.
Arathorn99c40582020-08-28 19:46:23 +0200497 input = SortInPairs(input);
MG Mud User88f12472016-06-24 23:31:02 +0200498 }
499
Arathorn815f2742020-08-28 17:29:04 +0200500 /* Alte Such-Treffer werden entsorgt. */
Arathornd0a1e662020-08-28 17:01:24 +0200501 oldman_result = 0;
502
Arathorn815f2742020-08-28 17:29:04 +0200503 /* <i> kann maximal eine einstellige Zahl sein, 1-9, wenn eine solche als
504 einziges Argument eingegeben wurde und kein passendes Ergebnis in einer
505 vorigen Suchanfrage gefunden wurde.
506
507 <input> kann nur genau dann mehr als 2 Elemente haben, wenn das Ergebnis
508 des Aufrufs MAND->locate() drinsteht. Und nur dann muss ueberhaupt ein
509 hoeheres Wertepaar rausgeschnitten werden, denn wenn <input> bis zu 2
510 Elemente hat, kann damit direkt weitergearbeitet werden.
511
512 Beispiel: bei einer Eingabe von "4" wird hier aus <input> das 7. und
513 8. Element entnommen (Indizes [6..7]). */
Arathorn131bb742020-08-28 17:05:02 +0200514 if(i && sizeof(input)>2 && sizeof(input) >= i*2)
515 input = input[(i*2-2)..(i*2-1)];
Arathornd0a1e662020-08-28 17:01:24 +0200516
Arathorn72c7e542020-08-28 16:50:28 +0200517 switch (sizeof(input))
MG Mud User88f12472016-06-24 23:31:02 +0200518 {
Arathorn815f2742020-08-28 17:29:04 +0200519 /* <input> leer, nichts brauchbares gefunden. */
MG Mud User88f12472016-06-24 23:31:02 +0200520 case 0:
Arathornd0a1e662020-08-28 17:01:24 +0200521 printf("Keine Hilfeseite gefunden fuer '%s'.\n", args[0]);
MG Mud User88f12472016-06-24 23:31:02 +0200522 break;
Arathornd0a1e662020-08-28 17:01:24 +0200523
Arathorn815f2742020-08-28 17:29:04 +0200524 /* Genau 2 Elemente enthalten? Dann kann das direkt ausgegeben werden. */
MG Mud User88f12472016-06-24 23:31:02 +0200525 case 2:
526 /*
527 if (flags&MAN_I)
528 {
529 // BRANCH TO MANUALD
530 return 1;
531 }
532 */
Arathorn72c7e542020-08-28 16:50:28 +0200533 printf("Folgende Hilfeseite wurde gefunden: %s\n", input[1]);
534 More(MAND_DOCDIR+input[1], 1);
MG Mud User88f12472016-06-24 23:31:02 +0200535 return 1;
Arathorn815f2742020-08-28 17:29:04 +0200536
537 /* Alles andere: */
MG Mud User88f12472016-06-24 23:31:02 +0200538 default:
Arathorn131bb742020-08-28 17:05:02 +0200539 i = sizeof(input)/2;
Arathorndb201cc2020-08-28 17:02:38 +0200540 string* output = allocate(i);
Arathorn815f2742020-08-28 17:29:04 +0200541
542 // Inhalt: ([ int nummer : string manpage; string manpage_pfad ])
Arathornd0a1e662020-08-28 17:01:24 +0200543 oldman_result = m_allocate(i, 2);
Arathorn815f2742020-08-28 17:29:04 +0200544
Arathornd0a1e662020-08-28 17:01:24 +0200545 while (i)
MG Mud User88f12472016-06-24 23:31:02 +0200546 {
Arathorn131bb742020-08-28 17:05:02 +0200547 output[i-1] = input[i*2-2];
Arathorn1719b252020-08-28 19:44:32 +0200548 m_add(oldman_result, i, input[i*2-2], input[i*2-1]);
MG Mud User88f12472016-06-24 23:31:02 +0200549 i--;
550 }
Arathorndb5d16d2020-05-11 01:23:18 +0200551
Arathorndb5d16d2020-05-11 01:23:18 +0200552 // Numerierung ergaenzen
Arathorndb201cc2020-08-28 17:02:38 +0200553 foreach(int j : sizeof(output))
Arathornd0a1e662020-08-28 17:01:24 +0200554 {
Arathorndb201cc2020-08-28 17:02:38 +0200555 output[j] = sprintf("%d: %s", j+1, output[j]);
Arathorndb5d16d2020-05-11 01:23:18 +0200556 }
557
558 int tty_cols = QueryProp(P_TTY_COLS)-2;
559 string list = "Es wurden die folgenden, potentiell passenden Seiten "
560 "gefunden:\n";
561
562 // Wer keine Grafik sehen will, bekommt eine andere Anzeige.
Arathornd0a1e662020-08-28 17:01:24 +0200563 if (QueryProp(P_NO_ASCII_ART))
564 {
Arathorndb5d16d2020-05-11 01:23:18 +0200565 // @ als geschuetztes Leerzeichen verwenden, um einen Umbruch
566 // nach den Nummern zu verhindern.
Arathorndb201cc2020-08-28 17:02:38 +0200567 output = map(output, #'regreplace, ": ", ":@", 1);
568 list += break_string(implode(output, " "), tty_cols);
Arathorndb5d16d2020-05-11 01:23:18 +0200569 list = regreplace(list, ":@", ": ", 1);
570 }
Arathornd0a1e662020-08-28 17:01:24 +0200571 else
572 {
Arathorndb5d16d2020-05-11 01:23:18 +0200573 // Anzahl Spalten ausrechnen: Terminalbreite / Laenge des laengsten
Arathorndb201cc2020-08-28 17:02:38 +0200574 // Elements in <output>. Kann der Spaltenmodus von sprintf() an sich
Arathorndb5d16d2020-05-11 01:23:18 +0200575 // selbst, das liefert aber nicht immer so guenstige Ergebnisse.
Arathorndb201cc2020-08-28 17:02:38 +0200576 int maxwidth = max(map(output, #'sizeof));
Arathorndb5d16d2020-05-11 01:23:18 +0200577 int tablecols = tty_cols/maxwidth;
578 list += "-"*tty_cols+"\n"+
Arathorndb201cc2020-08-28 17:02:38 +0200579 sprintf("%#-*.*s\n", tty_cols, tablecols, implode(output,"\n"))+
Arathorndb5d16d2020-05-11 01:23:18 +0200580 "-"*tty_cols+"\n";
581 }
582 printf(list);
MG Mud User88f12472016-06-24 23:31:02 +0200583 break;
584 }
585 return 1;
586}
587
588// ########
589//############################### RMAN ##################################
590// ########
591
592static int _rman(string str)
593{
594 int flags;
595 string *args;
596
597 str=_unparsed_args();
598 args=parseargs(str,&flags,"",0);
599 if (flags==-1||sizeof(args)!=2)
600 return USAGE("rman <hilfeseite> <mudname>");
601 write("man: " +
Vanion50652322020-03-10 21:13:25 +0100602 ({string})call_other(UDP_CMD_DIR+"man","send_request",args[1],args[0]));
MG Mud User88f12472016-06-24 23:31:02 +0200603 return 1;
604}
605
606
607// #############
608//############################# SHOWPROPS ###############################
609// #############
610
611//
612// _showprops: Zeigt Properties zu einem Objekt an
613//
614
615static int _showprops(string str)
616{
617 int i;
618 string *list, ausgabe;
619
620 if (str) {
621 if (str[0]!='/') str="/"+str;
622 if (str[0..4]!="/std/")
623 {
624 printf("showprops: Es koennen nur Properties von Objekten "
625 "aus /std/ angezeigt werden.\n");
626 return 1;
627 }
628 if (str[<1]=='.') str+="c";
629 if (str[<2..<1]!=".c") str+=".c";
630 if (file_size(str)<0)
631 {
632 printf("showprops: %s: Es gibt kein Objekt diesen Namens.\n",str[0..<3]);
633 return 1;
634 }
Zesstraefad7be2018-11-06 23:18:30 +0100635 if (catch(load_object(str)))
MG Mud User88f12472016-06-24 23:31:02 +0200636 {
637 printf("showprops: %s: Datei konnte nicht geladen werden.\n",str);
638 return 1;
639 }
640 }
641 if (!str || !find_object(str)) {
642 notify_fail("Welche Properties moechtest Du sehen?"
643 " Bsp.: <showprops /std/npc>\n");
644 return 0;
645 }
646 list=inherit_list(find_object(str));
MG Mud User88f12472016-06-24 23:31:02 +0200647 list=map(list,(: return $1[5..<2]+"h"; :));
648 list+=map(list,(: return explode($1,"/")[<1]; :));
649 list=map(m_indices(mkmapping(list)),(: return "/sys/"+$1; :));
650 list=filter(list,(: return file_size($1)>0; :));
MG Mud User88f12472016-06-24 23:31:02 +0200651 list=sort_array(list, #'<);
652 ausgabe="";
653 for (i=sizeof(list);i--;)
654 {
MG Mud User88f12472016-06-24 23:31:02 +0200655 str=implode(filter(explode(read_file(list[i]),"\n"),
656 (: return $1[0..9]=="#define P_";:)),"\n");
MG Mud User88f12472016-06-24 23:31:02 +0200657 if (str!="") ausgabe+=sprintf("%s\n%s\n\n", list[i], str);
658 }
659 if (ausgabe!="")
660 More(ausgabe);
661 else
662 printf("Keine Property-Definitionen zu diesem Objekt gefunden!\n");
663 return 1;
664}
665
666// ########
667//############################### GREP ###################################
668// ########
669
MG Mud User88f12472016-06-24 23:31:02 +0200670//
671// grep_file: Datei greppen
672// rexpr: Regular Expression
673// flags: Flags
674//
675
676private int grep_file(mixed filedata, string rexpr, int flags)
677{
Zesstrac70bf582019-11-26 00:43:17 +0100678 string fullname=filedata[FULLNAME];
MG Mud User88f12472016-06-24 23:31:02 +0200679 if ((flags&GREP_F)&&fullname=="/players/"+getuid()+"/grep.out")
Zesstraefad7be2018-11-06 23:18:30 +0100680 {
681 write_file("/players/"+getuid()+"/grep.out",
682 "Uebergehe grep.out ...\n");
683 return RET_FAIL;
MG Mud User88f12472016-06-24 23:31:02 +0200684 }
685 switch(filedata[FILESIZE])
686 {
Zesstraefad7be2018-11-06 23:18:30 +0100687 case FSIZE_DIR: return RET_FAIL;
688 case FSIZE_NOFILE: return ERROR(DOESNT_EXIST,fullname,RET_FAIL);
MG Mud User88f12472016-06-24 23:31:02 +0200689 case 0: return RET_FAIL;
690 default: break;
691 }
Zesstraefad7be2018-11-06 23:18:30 +0100692 if (!MAY_READ(fullname))
693 return ERROR(NO_READ,fullname,RET_FAIL);
Zesstrac70bf582019-11-26 00:43:17 +0100694
695 // Bei case-insensitiver Suche das Pattern in Kleinschreibung wandeln
MG Mud User88f12472016-06-24 23:31:02 +0200696 if (flags&GREP_I)
697 rexpr=lower_case(rexpr);
Zesstrac70bf582019-11-26 00:43:17 +0100698
699 // Portionsweise das komplette File einlesen.
700 int maxlen = query_limits()[LIMIT_BYTE];
701 int ptr;
702 bytes read_buffer;
703 bytes data = b"";
704 while (sizeof(read_buffer = read_bytes(fullname, ptr, maxlen)))
MG Mud User88f12472016-06-24 23:31:02 +0200705 {
Zesstrac70bf582019-11-26 00:43:17 +0100706 data += read_buffer;
707 ptr += sizeof(read_buffer);
708 // die Schleifenbedingung erkennt zwar auch, wenn das File vollstaendig
709 // ist, aber wir koennen den Speicherzugriff auch einsparen und schauen,
710 // ob wir schon alles haben.
711 if (ptr >= filedata[FILESIZE])
712 break;
MG Mud User88f12472016-06-24 23:31:02 +0200713 }
Zesstrac70bf582019-11-26 00:43:17 +0100714 // In string konvertieren, wir gehen davon aus, das File ist UTF8-kodiert.
715 string text = to_text(data, "UTF-8");
716 string *lines = explode(text, "\n");
717 int count; // Anzahl Zeilen mit Treffern
718 <string|string*> result = ({}); // zutreffende Zeilen
719 int linecount = 1;
720 foreach(string line: lines)
MG Mud User88f12472016-06-24 23:31:02 +0200721 {
Zesstrac70bf582019-11-26 00:43:17 +0100722 string orig_line = line;
723 // Suche case-insensitive?
724 if (flags&GREP_I)
725 line = lower_case(line);
726 int match = regmatch(line, rexpr) != 0;
727 if (flags&GREP_V) match = !match; // Match ggf. invertieren
MG Mud User88f12472016-06-24 23:31:02 +0200728 if (match)
729 {
Zesstrac70bf582019-11-26 00:43:17 +0100730 // Ausgeben oder nicht?
731 if (!(flags&GREP_C))
MG Mud User88f12472016-06-24 23:31:02 +0200732 {
Zesstrac70bf582019-11-26 00:43:17 +0100733 // Mit Zeilennummer?
734 if (flags&GREP_N)
735 result+=({ sprintf("%4d %s", linecount, orig_line)});
MG Mud User88f12472016-06-24 23:31:02 +0200736 else
Zesstrac70bf582019-11-26 00:43:17 +0100737 result+=({orig_line});
MG Mud User88f12472016-06-24 23:31:02 +0200738 }
Zesstrac70bf582019-11-26 00:43:17 +0100739 ++count;
MG Mud User88f12472016-06-24 23:31:02 +0200740 }
Zesstrac70bf582019-11-26 00:43:17 +0100741 ++linecount;
MG Mud User88f12472016-06-24 23:31:02 +0200742 }
Zesstrac70bf582019-11-26 00:43:17 +0100743
MG Mud User88f12472016-06-24 23:31:02 +0200744 if (count)
745 {
Zesstrac70bf582019-11-26 00:43:17 +0100746 // Bei -h werden die Dateinamen unterdrueckt.
747 if (flags&GREP_H)
748 fullname="";
MG Mud User88f12472016-06-24 23:31:02 +0200749 else
Zesstrac70bf582019-11-26 00:43:17 +0100750 fullname=sprintf("%s ",fullname);
751
752 if (flags&GREP_C)
753 result=sprintf("%s%d passende Zeile%s.\n",fullname, count,
754 (count==1?"":"n"));
755 else
756 result = ( (sizeof(fullname) ? fullname + "\n" : "")
757 + implode(result,"\n") + "\n");
Zesstrac70bf582019-11-26 00:43:17 +0100758
Zesstra77c0bf22020-01-07 22:27:27 +0100759 // Ergebnis ausgeben in File oder an Magier
760 if (flags&GREP_F)
761 return write_file("/players/"+getuid()+"/grep.out",result);
762 write(result);
763 }
MG Mud User88f12472016-06-24 23:31:02 +0200764 return RET_OK;
765}
766
767static int _grep(string cmdline)
768{
769 string rexpr,mask;
770 mixed *args;
771 int flags;
772 cmdline=_unparsed_args();
773 args=parseargs(cmdline,&flags,GREP_OPTS,0);
774 if ((flags==-1)||!sizeof(args))
775 return USAGE("grep [-" GREP_OPTS
776 "] <regexp> <datei/verz> [<datei2> ... ] [<maske>]");
777 rexpr=args[0];
778 if (catch(regexp(({""}),rexpr))||!regexp(({""}),rexpr))
779 return printf("grep: Ungueltiger Suchausdruck: %s\n",rexpr) ,1;
Zesstracc3f2502018-11-14 23:46:47 +0100780 args=(sizeof(args)>1 ? args[1..] : ({}) );
MG Mud User88f12472016-06-24 23:31:02 +0200781 if (flags&GREP_M)
782 {
783 mask=args[<1];
Zesstracc3f2502018-11-14 23:46:47 +0100784 if (sizeof(args) > 2)
785 args = (sizeof(args) > 1 ? args[0..<2] : ({}) );
MG Mud User88f12472016-06-24 23:31:02 +0200786 }
787 if (!sizeof(args))
788 return USAGE("grep [-" GREP_OPTS
789 "] <regexp> <datei/verz> [<datei2> ... ] [<maske>]");
790 args=map(args,#'to_filename)-({0});
MG Mud User88f12472016-06-24 23:31:02 +0200791 args=file_list(args,MODE_GREP,(flags&GREP_R?1:0),"/",mask);
792 if (!sizeof(args))
793 return printf("Keine passenden Dateien gefunden.\n"),1;
794 if (flags&GREP_I) rexpr=lower_case(rexpr);
795 if (flags&GREP_F)
796 {
Zesstraefad7be2018-11-06 23:18:30 +0100797 if (file_size("/players/"+getuid()+"/grep.out")==FSIZE_DIR
798 || !MAY_WRITE("/players/"+getuid()+"/grep.out"))
MG Mud User88f12472016-06-24 23:31:02 +0200799 return printf("grep: Datei /players/%s/grep.out kann nicht "
Zesstraefad7be2018-11-06 23:18:30 +0100800 "geschrieben werden.\n",getuid()),1;
MG Mud User88f12472016-06-24 23:31:02 +0200801 else
802 write_file("/players/"+getuid()+"/grep.out",
803 "Ausgabe von \"grep " + _unparsed_args() + "\":\n");
804 }
805 asynchron(args,#'grep_file,rexpr,flags,0);
806 return 1;
807}