blob: 0db06f6a28a6a202fed5e6a3aee0d7bc4f2537e7 [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
412static int _man(string cmdline)
413{
MG Mud User88f12472016-06-24 23:31:02 +0200414 int i, flags;
Arathorndb201cc2020-08-28 17:02:38 +0200415 string *input;
MG Mud User88f12472016-06-24 23:31:02 +0200416
Arathorn1facd5f2020-08-28 16:41:17 +0200417 string* args = parseargs(_unparsed_args(), &flags, MAN_OPTS, 0);
418
MG Mud User88f12472016-06-24 23:31:02 +0200419 if (flags==-1 ||
420 (sizeof(args)!=1 &&
421 (sizeof(args)<2 || sizeof(args[1])>1 || !(i=to_int(args[1])))))
422 return USAGE("man [-" MAN_OPTS "] <hilfeseite>");
MG Mud User88f12472016-06-24 23:31:02 +0200423
Arathorn72c7e542020-08-28 16:50:28 +0200424 input = explode(args[0], "/");
425
Arathorn815f2742020-08-28 17:29:04 +0200426 /* Wenn das Ergebnis einer vorherigen Suche noch vorliegt und die aktuelle
427 Eingabe als einziges eine einstellige Zahl enthaelt, und diese dann in
428 dem alten Suchergebnis enthalten ist, wird die Eingabe durch das alte
429 Ergebnis ersetzt. <i> wird in dem Fall geloescht.
430 Wenn kein altes Ergebnis gefunden wurde, enthaelt <i> die eingegebene
431 Nummer. */
Arathorn72c7e542020-08-28 16:50:28 +0200432 if (oldman_result && sizeof(input)==1 && sizeof(args)==1 &&
433 sizeof(input[0])==1 && (i=to_int(input[0])) &&
Arathornd0a1e662020-08-28 17:01:24 +0200434 member(oldman_result,i))
435 {
Arathorn72c7e542020-08-28 16:50:28 +0200436 input = ({oldman_result[i,0], oldman_result[i,1]});
Arathornd0a1e662020-08-28 17:01:24 +0200437 i = 0;
MG Mud User88f12472016-06-24 23:31:02 +0200438 }
Arathorn815f2742020-08-28 17:29:04 +0200439 /* Ansonsten wenn weder -m, noch -r gesetzt sind und es eine Manpage gibt,
440 die genau der Eingabe entspricht, wird diese verwendet. */
Arathorn72c7e542020-08-28 16:50:28 +0200441 else if (!(flags&(MAN_M|MAN_R)) && sizeof(input)>1)
MG Mud User88f12472016-06-24 23:31:02 +0200442 {
Arathornd0a1e662020-08-28 17:01:24 +0200443 if (file_size(MAND_DOCDIR+args[0]) >= 0)
Arathorn72c7e542020-08-28 16:50:28 +0200444 input = ({input[<1], args[0]});
MG Mud User88f12472016-06-24 23:31:02 +0200445 else
Arathorn72c7e542020-08-28 16:50:28 +0200446 input = ({});
MG Mud User88f12472016-06-24 23:31:02 +0200447 }
448 else
449 {
Arathorn815f2742020-08-28 17:29:04 +0200450 /* Soll eine Regexp-Suche durchgefuehrt werden? Dann erstmal den Ausdruck
451 auf Gueltigkeit pruefen. */
MG Mud User88f12472016-06-24 23:31:02 +0200452 if (flags&MAN_R)
453 {
Arathornd0a1e662020-08-28 17:01:24 +0200454 flags &= (~MAN_M);
455 if (catch(regexp(({""}), args[0])) || !regexp(({""}), args[0]))
456 {
457 printf("man: Ungueltiger Ausdruck in Maske.\n");
458 return 1;
459 }
MG Mud User88f12472016-06-24 23:31:02 +0200460 }
Arathorn815f2742020-08-28 17:29:04 +0200461 /* Die Ausgabe von locate() liefert ein String-Array, das abwechselnd den
462 Dateinamen der gefundenen Manpage und den vollen Pfad dieser Manpage
463 unterhalb von /doc enthaelt. Beispielsweise ({"Defend","lfun/Defend"})
464 */
Arathorn72c7e542020-08-28 16:50:28 +0200465 input = ({string *})MAND->locate(args[0], flags&(MAN_M|MAN_R));
Arathorn84dd5f22020-08-28 17:24:44 +0200466 // Sortierung case-insensitive, ggf. vorhandene Pfade dabei ignorieren
467 // Wird fuer die spaetere Ausgabe der Liste benoetigt.
468 input = sort_array(input, function int (string t1, string t2)
469 {
470 t1 = explode(t1, "/")[<1];
471 t2 = explode(t2, "/")[<1];
472 return lower_case(t1) > lower_case(t2);
473 });
MG Mud User88f12472016-06-24 23:31:02 +0200474 }
475
Arathorn815f2742020-08-28 17:29:04 +0200476 /* Alte Such-Treffer werden entsorgt. */
Arathornd0a1e662020-08-28 17:01:24 +0200477 oldman_result = 0;
478
Arathorn815f2742020-08-28 17:29:04 +0200479 /* <i> kann maximal eine einstellige Zahl sein, 1-9, wenn eine solche als
480 einziges Argument eingegeben wurde und kein passendes Ergebnis in einer
481 vorigen Suchanfrage gefunden wurde.
482
483 <input> kann nur genau dann mehr als 2 Elemente haben, wenn das Ergebnis
484 des Aufrufs MAND->locate() drinsteht. Und nur dann muss ueberhaupt ein
485 hoeheres Wertepaar rausgeschnitten werden, denn wenn <input> bis zu 2
486 Elemente hat, kann damit direkt weitergearbeitet werden.
487
488 Beispiel: bei einer Eingabe von "4" wird hier aus <input> das 7. und
489 8. Element entnommen (Indizes [6..7]). */
Arathorn131bb742020-08-28 17:05:02 +0200490 if(i && sizeof(input)>2 && sizeof(input) >= i*2)
491 input = input[(i*2-2)..(i*2-1)];
Arathornd0a1e662020-08-28 17:01:24 +0200492
Arathorn72c7e542020-08-28 16:50:28 +0200493 switch (sizeof(input))
MG Mud User88f12472016-06-24 23:31:02 +0200494 {
Arathorn815f2742020-08-28 17:29:04 +0200495 /* <input> leer, nichts brauchbares gefunden. */
MG Mud User88f12472016-06-24 23:31:02 +0200496 case 0:
Arathornd0a1e662020-08-28 17:01:24 +0200497 printf("Keine Hilfeseite gefunden fuer '%s'.\n", args[0]);
MG Mud User88f12472016-06-24 23:31:02 +0200498 break;
Arathornd0a1e662020-08-28 17:01:24 +0200499
Arathorn815f2742020-08-28 17:29:04 +0200500 /* Genau 2 Elemente enthalten? Dann kann das direkt ausgegeben werden. */
MG Mud User88f12472016-06-24 23:31:02 +0200501 case 2:
502 /*
503 if (flags&MAN_I)
504 {
505 // BRANCH TO MANUALD
506 return 1;
507 }
508 */
Arathorn72c7e542020-08-28 16:50:28 +0200509 printf("Folgende Hilfeseite wurde gefunden: %s\n", input[1]);
510 More(MAND_DOCDIR+input[1], 1);
MG Mud User88f12472016-06-24 23:31:02 +0200511 return 1;
Arathorn815f2742020-08-28 17:29:04 +0200512
513 /* Alles andere: */
MG Mud User88f12472016-06-24 23:31:02 +0200514 default:
Arathorn131bb742020-08-28 17:05:02 +0200515 i = sizeof(input)/2;
Arathorndb201cc2020-08-28 17:02:38 +0200516 string* output = allocate(i);
Arathorn815f2742020-08-28 17:29:04 +0200517
518 // Inhalt: ([ int nummer : string manpage; string manpage_pfad ])
Arathornd0a1e662020-08-28 17:01:24 +0200519 oldman_result = m_allocate(i, 2);
Arathorn815f2742020-08-28 17:29:04 +0200520
Arathornd0a1e662020-08-28 17:01:24 +0200521 while (i)
MG Mud User88f12472016-06-24 23:31:02 +0200522 {
Arathorn131bb742020-08-28 17:05:02 +0200523 output[i-1] = input[i*2-2];
Arathorn1719b252020-08-28 19:44:32 +0200524 m_add(oldman_result, i, input[i*2-2], input[i*2-1]);
MG Mud User88f12472016-06-24 23:31:02 +0200525 i--;
526 }
Arathorndb5d16d2020-05-11 01:23:18 +0200527
Arathorndb5d16d2020-05-11 01:23:18 +0200528 // Numerierung ergaenzen
Arathorndb201cc2020-08-28 17:02:38 +0200529 foreach(int j : sizeof(output))
Arathornd0a1e662020-08-28 17:01:24 +0200530 {
Arathorndb201cc2020-08-28 17:02:38 +0200531 output[j] = sprintf("%d: %s", j+1, output[j]);
Arathorndb5d16d2020-05-11 01:23:18 +0200532 }
533
534 int tty_cols = QueryProp(P_TTY_COLS)-2;
535 string list = "Es wurden die folgenden, potentiell passenden Seiten "
536 "gefunden:\n";
537
538 // Wer keine Grafik sehen will, bekommt eine andere Anzeige.
Arathornd0a1e662020-08-28 17:01:24 +0200539 if (QueryProp(P_NO_ASCII_ART))
540 {
Arathorndb5d16d2020-05-11 01:23:18 +0200541 // @ als geschuetztes Leerzeichen verwenden, um einen Umbruch
542 // nach den Nummern zu verhindern.
Arathorndb201cc2020-08-28 17:02:38 +0200543 output = map(output, #'regreplace, ": ", ":@", 1);
544 list += break_string(implode(output, " "), tty_cols);
Arathorndb5d16d2020-05-11 01:23:18 +0200545 list = regreplace(list, ":@", ": ", 1);
546 }
Arathornd0a1e662020-08-28 17:01:24 +0200547 else
548 {
Arathorndb5d16d2020-05-11 01:23:18 +0200549 // Anzahl Spalten ausrechnen: Terminalbreite / Laenge des laengsten
Arathorndb201cc2020-08-28 17:02:38 +0200550 // Elements in <output>. Kann der Spaltenmodus von sprintf() an sich
Arathorndb5d16d2020-05-11 01:23:18 +0200551 // selbst, das liefert aber nicht immer so guenstige Ergebnisse.
Arathorndb201cc2020-08-28 17:02:38 +0200552 int maxwidth = max(map(output, #'sizeof));
Arathorndb5d16d2020-05-11 01:23:18 +0200553 int tablecols = tty_cols/maxwidth;
554 list += "-"*tty_cols+"\n"+
Arathorndb201cc2020-08-28 17:02:38 +0200555 sprintf("%#-*.*s\n", tty_cols, tablecols, implode(output,"\n"))+
Arathorndb5d16d2020-05-11 01:23:18 +0200556 "-"*tty_cols+"\n";
557 }
558 printf(list);
MG Mud User88f12472016-06-24 23:31:02 +0200559 break;
560 }
561 return 1;
562}
563
564// ########
565//############################### RMAN ##################################
566// ########
567
568static int _rman(string str)
569{
570 int flags;
571 string *args;
572
573 str=_unparsed_args();
574 args=parseargs(str,&flags,"",0);
575 if (flags==-1||sizeof(args)!=2)
576 return USAGE("rman <hilfeseite> <mudname>");
577 write("man: " +
Vanion50652322020-03-10 21:13:25 +0100578 ({string})call_other(UDP_CMD_DIR+"man","send_request",args[1],args[0]));
MG Mud User88f12472016-06-24 23:31:02 +0200579 return 1;
580}
581
582
583// #############
584//############################# SHOWPROPS ###############################
585// #############
586
587//
588// _showprops: Zeigt Properties zu einem Objekt an
589//
590
591static int _showprops(string str)
592{
593 int i;
594 string *list, ausgabe;
595
596 if (str) {
597 if (str[0]!='/') str="/"+str;
598 if (str[0..4]!="/std/")
599 {
600 printf("showprops: Es koennen nur Properties von Objekten "
601 "aus /std/ angezeigt werden.\n");
602 return 1;
603 }
604 if (str[<1]=='.') str+="c";
605 if (str[<2..<1]!=".c") str+=".c";
606 if (file_size(str)<0)
607 {
608 printf("showprops: %s: Es gibt kein Objekt diesen Namens.\n",str[0..<3]);
609 return 1;
610 }
Zesstraefad7be2018-11-06 23:18:30 +0100611 if (catch(load_object(str)))
MG Mud User88f12472016-06-24 23:31:02 +0200612 {
613 printf("showprops: %s: Datei konnte nicht geladen werden.\n",str);
614 return 1;
615 }
616 }
617 if (!str || !find_object(str)) {
618 notify_fail("Welche Properties moechtest Du sehen?"
619 " Bsp.: <showprops /std/npc>\n");
620 return 0;
621 }
622 list=inherit_list(find_object(str));
MG Mud User88f12472016-06-24 23:31:02 +0200623 list=map(list,(: return $1[5..<2]+"h"; :));
624 list+=map(list,(: return explode($1,"/")[<1]; :));
625 list=map(m_indices(mkmapping(list)),(: return "/sys/"+$1; :));
626 list=filter(list,(: return file_size($1)>0; :));
MG Mud User88f12472016-06-24 23:31:02 +0200627 list=sort_array(list, #'<);
628 ausgabe="";
629 for (i=sizeof(list);i--;)
630 {
MG Mud User88f12472016-06-24 23:31:02 +0200631 str=implode(filter(explode(read_file(list[i]),"\n"),
632 (: return $1[0..9]=="#define P_";:)),"\n");
MG Mud User88f12472016-06-24 23:31:02 +0200633 if (str!="") ausgabe+=sprintf("%s\n%s\n\n", list[i], str);
634 }
635 if (ausgabe!="")
636 More(ausgabe);
637 else
638 printf("Keine Property-Definitionen zu diesem Objekt gefunden!\n");
639 return 1;
640}
641
642// ########
643//############################### GREP ###################################
644// ########
645
MG Mud User88f12472016-06-24 23:31:02 +0200646//
647// grep_file: Datei greppen
648// rexpr: Regular Expression
649// flags: Flags
650//
651
652private int grep_file(mixed filedata, string rexpr, int flags)
653{
Zesstrac70bf582019-11-26 00:43:17 +0100654 string fullname=filedata[FULLNAME];
MG Mud User88f12472016-06-24 23:31:02 +0200655 if ((flags&GREP_F)&&fullname=="/players/"+getuid()+"/grep.out")
Zesstraefad7be2018-11-06 23:18:30 +0100656 {
657 write_file("/players/"+getuid()+"/grep.out",
658 "Uebergehe grep.out ...\n");
659 return RET_FAIL;
MG Mud User88f12472016-06-24 23:31:02 +0200660 }
661 switch(filedata[FILESIZE])
662 {
Zesstraefad7be2018-11-06 23:18:30 +0100663 case FSIZE_DIR: return RET_FAIL;
664 case FSIZE_NOFILE: return ERROR(DOESNT_EXIST,fullname,RET_FAIL);
MG Mud User88f12472016-06-24 23:31:02 +0200665 case 0: return RET_FAIL;
666 default: break;
667 }
Zesstraefad7be2018-11-06 23:18:30 +0100668 if (!MAY_READ(fullname))
669 return ERROR(NO_READ,fullname,RET_FAIL);
Zesstrac70bf582019-11-26 00:43:17 +0100670
671 // Bei case-insensitiver Suche das Pattern in Kleinschreibung wandeln
MG Mud User88f12472016-06-24 23:31:02 +0200672 if (flags&GREP_I)
673 rexpr=lower_case(rexpr);
Zesstrac70bf582019-11-26 00:43:17 +0100674
675 // Portionsweise das komplette File einlesen.
676 int maxlen = query_limits()[LIMIT_BYTE];
677 int ptr;
678 bytes read_buffer;
679 bytes data = b"";
680 while (sizeof(read_buffer = read_bytes(fullname, ptr, maxlen)))
MG Mud User88f12472016-06-24 23:31:02 +0200681 {
Zesstrac70bf582019-11-26 00:43:17 +0100682 data += read_buffer;
683 ptr += sizeof(read_buffer);
684 // die Schleifenbedingung erkennt zwar auch, wenn das File vollstaendig
685 // ist, aber wir koennen den Speicherzugriff auch einsparen und schauen,
686 // ob wir schon alles haben.
687 if (ptr >= filedata[FILESIZE])
688 break;
MG Mud User88f12472016-06-24 23:31:02 +0200689 }
Zesstrac70bf582019-11-26 00:43:17 +0100690 // In string konvertieren, wir gehen davon aus, das File ist UTF8-kodiert.
691 string text = to_text(data, "UTF-8");
692 string *lines = explode(text, "\n");
693 int count; // Anzahl Zeilen mit Treffern
694 <string|string*> result = ({}); // zutreffende Zeilen
695 int linecount = 1;
696 foreach(string line: lines)
MG Mud User88f12472016-06-24 23:31:02 +0200697 {
Zesstrac70bf582019-11-26 00:43:17 +0100698 string orig_line = line;
699 // Suche case-insensitive?
700 if (flags&GREP_I)
701 line = lower_case(line);
702 int match = regmatch(line, rexpr) != 0;
703 if (flags&GREP_V) match = !match; // Match ggf. invertieren
MG Mud User88f12472016-06-24 23:31:02 +0200704 if (match)
705 {
Zesstrac70bf582019-11-26 00:43:17 +0100706 // Ausgeben oder nicht?
707 if (!(flags&GREP_C))
MG Mud User88f12472016-06-24 23:31:02 +0200708 {
Zesstrac70bf582019-11-26 00:43:17 +0100709 // Mit Zeilennummer?
710 if (flags&GREP_N)
711 result+=({ sprintf("%4d %s", linecount, orig_line)});
MG Mud User88f12472016-06-24 23:31:02 +0200712 else
Zesstrac70bf582019-11-26 00:43:17 +0100713 result+=({orig_line});
MG Mud User88f12472016-06-24 23:31:02 +0200714 }
Zesstrac70bf582019-11-26 00:43:17 +0100715 ++count;
MG Mud User88f12472016-06-24 23:31:02 +0200716 }
Zesstrac70bf582019-11-26 00:43:17 +0100717 ++linecount;
MG Mud User88f12472016-06-24 23:31:02 +0200718 }
Zesstrac70bf582019-11-26 00:43:17 +0100719
MG Mud User88f12472016-06-24 23:31:02 +0200720 if (count)
721 {
Zesstrac70bf582019-11-26 00:43:17 +0100722 // Bei -h werden die Dateinamen unterdrueckt.
723 if (flags&GREP_H)
724 fullname="";
MG Mud User88f12472016-06-24 23:31:02 +0200725 else
Zesstrac70bf582019-11-26 00:43:17 +0100726 fullname=sprintf("%s ",fullname);
727
728 if (flags&GREP_C)
729 result=sprintf("%s%d passende Zeile%s.\n",fullname, count,
730 (count==1?"":"n"));
731 else
732 result = ( (sizeof(fullname) ? fullname + "\n" : "")
733 + implode(result,"\n") + "\n");
Zesstrac70bf582019-11-26 00:43:17 +0100734
Zesstra77c0bf22020-01-07 22:27:27 +0100735 // Ergebnis ausgeben in File oder an Magier
736 if (flags&GREP_F)
737 return write_file("/players/"+getuid()+"/grep.out",result);
738 write(result);
739 }
MG Mud User88f12472016-06-24 23:31:02 +0200740 return RET_OK;
741}
742
743static int _grep(string cmdline)
744{
745 string rexpr,mask;
746 mixed *args;
747 int flags;
748 cmdline=_unparsed_args();
749 args=parseargs(cmdline,&flags,GREP_OPTS,0);
750 if ((flags==-1)||!sizeof(args))
751 return USAGE("grep [-" GREP_OPTS
752 "] <regexp> <datei/verz> [<datei2> ... ] [<maske>]");
753 rexpr=args[0];
754 if (catch(regexp(({""}),rexpr))||!regexp(({""}),rexpr))
755 return printf("grep: Ungueltiger Suchausdruck: %s\n",rexpr) ,1;
Zesstracc3f2502018-11-14 23:46:47 +0100756 args=(sizeof(args)>1 ? args[1..] : ({}) );
MG Mud User88f12472016-06-24 23:31:02 +0200757 if (flags&GREP_M)
758 {
759 mask=args[<1];
Zesstracc3f2502018-11-14 23:46:47 +0100760 if (sizeof(args) > 2)
761 args = (sizeof(args) > 1 ? args[0..<2] : ({}) );
MG Mud User88f12472016-06-24 23:31:02 +0200762 }
763 if (!sizeof(args))
764 return USAGE("grep [-" GREP_OPTS
765 "] <regexp> <datei/verz> [<datei2> ... ] [<maske>]");
766 args=map(args,#'to_filename)-({0});
MG Mud User88f12472016-06-24 23:31:02 +0200767 args=file_list(args,MODE_GREP,(flags&GREP_R?1:0),"/",mask);
768 if (!sizeof(args))
769 return printf("Keine passenden Dateien gefunden.\n"),1;
770 if (flags&GREP_I) rexpr=lower_case(rexpr);
771 if (flags&GREP_F)
772 {
Zesstraefad7be2018-11-06 23:18:30 +0100773 if (file_size("/players/"+getuid()+"/grep.out")==FSIZE_DIR
774 || !MAY_WRITE("/players/"+getuid()+"/grep.out"))
MG Mud User88f12472016-06-24 23:31:02 +0200775 return printf("grep: Datei /players/%s/grep.out kann nicht "
Zesstraefad7be2018-11-06 23:18:30 +0100776 "geschrieben werden.\n",getuid()),1;
MG Mud User88f12472016-06-24 23:31:02 +0200777 else
778 write_file("/players/"+getuid()+"/grep.out",
779 "Ausgabe von \"grep " + _unparsed_args() + "\":\n");
780 }
781 asynchron(args,#'grep_file,rexpr,flags,0);
782 return 1;
783}