blob: 68bf49af7ddc9c69515a6e52962ced1f9965adb5 [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];
524 oldman_result[i,0] = input[i*2-2];
525 oldman_result[i,1] = input[i*2-1];
MG Mud User88f12472016-06-24 23:31:02 +0200526 i--;
527 }
Arathorndb5d16d2020-05-11 01:23:18 +0200528
Arathorndb5d16d2020-05-11 01:23:18 +0200529 // Numerierung ergaenzen
Arathorndb201cc2020-08-28 17:02:38 +0200530 foreach(int j : sizeof(output))
Arathornd0a1e662020-08-28 17:01:24 +0200531 {
Arathorndb201cc2020-08-28 17:02:38 +0200532 output[j] = sprintf("%d: %s", j+1, output[j]);
Arathorndb5d16d2020-05-11 01:23:18 +0200533 }
534
535 int tty_cols = QueryProp(P_TTY_COLS)-2;
536 string list = "Es wurden die folgenden, potentiell passenden Seiten "
537 "gefunden:\n";
538
539 // Wer keine Grafik sehen will, bekommt eine andere Anzeige.
Arathornd0a1e662020-08-28 17:01:24 +0200540 if (QueryProp(P_NO_ASCII_ART))
541 {
Arathorndb5d16d2020-05-11 01:23:18 +0200542 // @ als geschuetztes Leerzeichen verwenden, um einen Umbruch
543 // nach den Nummern zu verhindern.
Arathorndb201cc2020-08-28 17:02:38 +0200544 output = map(output, #'regreplace, ": ", ":@", 1);
545 list += break_string(implode(output, " "), tty_cols);
Arathorndb5d16d2020-05-11 01:23:18 +0200546 list = regreplace(list, ":@", ": ", 1);
547 }
Arathornd0a1e662020-08-28 17:01:24 +0200548 else
549 {
Arathorndb5d16d2020-05-11 01:23:18 +0200550 // Anzahl Spalten ausrechnen: Terminalbreite / Laenge des laengsten
Arathorndb201cc2020-08-28 17:02:38 +0200551 // Elements in <output>. Kann der Spaltenmodus von sprintf() an sich
Arathorndb5d16d2020-05-11 01:23:18 +0200552 // selbst, das liefert aber nicht immer so guenstige Ergebnisse.
Arathorndb201cc2020-08-28 17:02:38 +0200553 int maxwidth = max(map(output, #'sizeof));
Arathorndb5d16d2020-05-11 01:23:18 +0200554 int tablecols = tty_cols/maxwidth;
555 list += "-"*tty_cols+"\n"+
Arathorndb201cc2020-08-28 17:02:38 +0200556 sprintf("%#-*.*s\n", tty_cols, tablecols, implode(output,"\n"))+
Arathorndb5d16d2020-05-11 01:23:18 +0200557 "-"*tty_cols+"\n";
558 }
559 printf(list);
MG Mud User88f12472016-06-24 23:31:02 +0200560 break;
561 }
562 return 1;
563}
564
565// ########
566//############################### RMAN ##################################
567// ########
568
569static int _rman(string str)
570{
571 int flags;
572 string *args;
573
574 str=_unparsed_args();
575 args=parseargs(str,&flags,"",0);
576 if (flags==-1||sizeof(args)!=2)
577 return USAGE("rman <hilfeseite> <mudname>");
578 write("man: " +
Vanion50652322020-03-10 21:13:25 +0100579 ({string})call_other(UDP_CMD_DIR+"man","send_request",args[1],args[0]));
MG Mud User88f12472016-06-24 23:31:02 +0200580 return 1;
581}
582
583
584// #############
585//############################# SHOWPROPS ###############################
586// #############
587
588//
589// _showprops: Zeigt Properties zu einem Objekt an
590//
591
592static int _showprops(string str)
593{
594 int i;
595 string *list, ausgabe;
596
597 if (str) {
598 if (str[0]!='/') str="/"+str;
599 if (str[0..4]!="/std/")
600 {
601 printf("showprops: Es koennen nur Properties von Objekten "
602 "aus /std/ angezeigt werden.\n");
603 return 1;
604 }
605 if (str[<1]=='.') str+="c";
606 if (str[<2..<1]!=".c") str+=".c";
607 if (file_size(str)<0)
608 {
609 printf("showprops: %s: Es gibt kein Objekt diesen Namens.\n",str[0..<3]);
610 return 1;
611 }
Zesstraefad7be2018-11-06 23:18:30 +0100612 if (catch(load_object(str)))
MG Mud User88f12472016-06-24 23:31:02 +0200613 {
614 printf("showprops: %s: Datei konnte nicht geladen werden.\n",str);
615 return 1;
616 }
617 }
618 if (!str || !find_object(str)) {
619 notify_fail("Welche Properties moechtest Du sehen?"
620 " Bsp.: <showprops /std/npc>\n");
621 return 0;
622 }
623 list=inherit_list(find_object(str));
MG Mud User88f12472016-06-24 23:31:02 +0200624 list=map(list,(: return $1[5..<2]+"h"; :));
625 list+=map(list,(: return explode($1,"/")[<1]; :));
626 list=map(m_indices(mkmapping(list)),(: return "/sys/"+$1; :));
627 list=filter(list,(: return file_size($1)>0; :));
MG Mud User88f12472016-06-24 23:31:02 +0200628 list=sort_array(list, #'<);
629 ausgabe="";
630 for (i=sizeof(list);i--;)
631 {
MG Mud User88f12472016-06-24 23:31:02 +0200632 str=implode(filter(explode(read_file(list[i]),"\n"),
633 (: return $1[0..9]=="#define P_";:)),"\n");
MG Mud User88f12472016-06-24 23:31:02 +0200634 if (str!="") ausgabe+=sprintf("%s\n%s\n\n", list[i], str);
635 }
636 if (ausgabe!="")
637 More(ausgabe);
638 else
639 printf("Keine Property-Definitionen zu diesem Objekt gefunden!\n");
640 return 1;
641}
642
643// ########
644//############################### GREP ###################################
645// ########
646
MG Mud User88f12472016-06-24 23:31:02 +0200647//
648// grep_file: Datei greppen
649// rexpr: Regular Expression
650// flags: Flags
651//
652
653private int grep_file(mixed filedata, string rexpr, int flags)
654{
Zesstrac70bf582019-11-26 00:43:17 +0100655 string fullname=filedata[FULLNAME];
MG Mud User88f12472016-06-24 23:31:02 +0200656 if ((flags&GREP_F)&&fullname=="/players/"+getuid()+"/grep.out")
Zesstraefad7be2018-11-06 23:18:30 +0100657 {
658 write_file("/players/"+getuid()+"/grep.out",
659 "Uebergehe grep.out ...\n");
660 return RET_FAIL;
MG Mud User88f12472016-06-24 23:31:02 +0200661 }
662 switch(filedata[FILESIZE])
663 {
Zesstraefad7be2018-11-06 23:18:30 +0100664 case FSIZE_DIR: return RET_FAIL;
665 case FSIZE_NOFILE: return ERROR(DOESNT_EXIST,fullname,RET_FAIL);
MG Mud User88f12472016-06-24 23:31:02 +0200666 case 0: return RET_FAIL;
667 default: break;
668 }
Zesstraefad7be2018-11-06 23:18:30 +0100669 if (!MAY_READ(fullname))
670 return ERROR(NO_READ,fullname,RET_FAIL);
Zesstrac70bf582019-11-26 00:43:17 +0100671
672 // Bei case-insensitiver Suche das Pattern in Kleinschreibung wandeln
MG Mud User88f12472016-06-24 23:31:02 +0200673 if (flags&GREP_I)
674 rexpr=lower_case(rexpr);
Zesstrac70bf582019-11-26 00:43:17 +0100675
676 // Portionsweise das komplette File einlesen.
677 int maxlen = query_limits()[LIMIT_BYTE];
678 int ptr;
679 bytes read_buffer;
680 bytes data = b"";
681 while (sizeof(read_buffer = read_bytes(fullname, ptr, maxlen)))
MG Mud User88f12472016-06-24 23:31:02 +0200682 {
Zesstrac70bf582019-11-26 00:43:17 +0100683 data += read_buffer;
684 ptr += sizeof(read_buffer);
685 // die Schleifenbedingung erkennt zwar auch, wenn das File vollstaendig
686 // ist, aber wir koennen den Speicherzugriff auch einsparen und schauen,
687 // ob wir schon alles haben.
688 if (ptr >= filedata[FILESIZE])
689 break;
MG Mud User88f12472016-06-24 23:31:02 +0200690 }
Zesstrac70bf582019-11-26 00:43:17 +0100691 // In string konvertieren, wir gehen davon aus, das File ist UTF8-kodiert.
692 string text = to_text(data, "UTF-8");
693 string *lines = explode(text, "\n");
694 int count; // Anzahl Zeilen mit Treffern
695 <string|string*> result = ({}); // zutreffende Zeilen
696 int linecount = 1;
697 foreach(string line: lines)
MG Mud User88f12472016-06-24 23:31:02 +0200698 {
Zesstrac70bf582019-11-26 00:43:17 +0100699 string orig_line = line;
700 // Suche case-insensitive?
701 if (flags&GREP_I)
702 line = lower_case(line);
703 int match = regmatch(line, rexpr) != 0;
704 if (flags&GREP_V) match = !match; // Match ggf. invertieren
MG Mud User88f12472016-06-24 23:31:02 +0200705 if (match)
706 {
Zesstrac70bf582019-11-26 00:43:17 +0100707 // Ausgeben oder nicht?
708 if (!(flags&GREP_C))
MG Mud User88f12472016-06-24 23:31:02 +0200709 {
Zesstrac70bf582019-11-26 00:43:17 +0100710 // Mit Zeilennummer?
711 if (flags&GREP_N)
712 result+=({ sprintf("%4d %s", linecount, orig_line)});
MG Mud User88f12472016-06-24 23:31:02 +0200713 else
Zesstrac70bf582019-11-26 00:43:17 +0100714 result+=({orig_line});
MG Mud User88f12472016-06-24 23:31:02 +0200715 }
Zesstrac70bf582019-11-26 00:43:17 +0100716 ++count;
MG Mud User88f12472016-06-24 23:31:02 +0200717 }
Zesstrac70bf582019-11-26 00:43:17 +0100718 ++linecount;
MG Mud User88f12472016-06-24 23:31:02 +0200719 }
Zesstrac70bf582019-11-26 00:43:17 +0100720
MG Mud User88f12472016-06-24 23:31:02 +0200721 if (count)
722 {
Zesstrac70bf582019-11-26 00:43:17 +0100723 // Bei -h werden die Dateinamen unterdrueckt.
724 if (flags&GREP_H)
725 fullname="";
MG Mud User88f12472016-06-24 23:31:02 +0200726 else
Zesstrac70bf582019-11-26 00:43:17 +0100727 fullname=sprintf("%s ",fullname);
728
729 if (flags&GREP_C)
730 result=sprintf("%s%d passende Zeile%s.\n",fullname, count,
731 (count==1?"":"n"));
732 else
733 result = ( (sizeof(fullname) ? fullname + "\n" : "")
734 + implode(result,"\n") + "\n");
Zesstrac70bf582019-11-26 00:43:17 +0100735
Zesstra77c0bf22020-01-07 22:27:27 +0100736 // Ergebnis ausgeben in File oder an Magier
737 if (flags&GREP_F)
738 return write_file("/players/"+getuid()+"/grep.out",result);
739 write(result);
740 }
MG Mud User88f12472016-06-24 23:31:02 +0200741 return RET_OK;
742}
743
744static int _grep(string cmdline)
745{
746 string rexpr,mask;
747 mixed *args;
748 int flags;
749 cmdline=_unparsed_args();
750 args=parseargs(cmdline,&flags,GREP_OPTS,0);
751 if ((flags==-1)||!sizeof(args))
752 return USAGE("grep [-" GREP_OPTS
753 "] <regexp> <datei/verz> [<datei2> ... ] [<maske>]");
754 rexpr=args[0];
755 if (catch(regexp(({""}),rexpr))||!regexp(({""}),rexpr))
756 return printf("grep: Ungueltiger Suchausdruck: %s\n",rexpr) ,1;
Zesstracc3f2502018-11-14 23:46:47 +0100757 args=(sizeof(args)>1 ? args[1..] : ({}) );
MG Mud User88f12472016-06-24 23:31:02 +0200758 if (flags&GREP_M)
759 {
760 mask=args[<1];
Zesstracc3f2502018-11-14 23:46:47 +0100761 if (sizeof(args) > 2)
762 args = (sizeof(args) > 1 ? args[0..<2] : ({}) );
MG Mud User88f12472016-06-24 23:31:02 +0200763 }
764 if (!sizeof(args))
765 return USAGE("grep [-" GREP_OPTS
766 "] <regexp> <datei/verz> [<datei2> ... ] [<maske>]");
767 args=map(args,#'to_filename)-({0});
MG Mud User88f12472016-06-24 23:31:02 +0200768 args=file_list(args,MODE_GREP,(flags&GREP_R?1:0),"/",mask);
769 if (!sizeof(args))
770 return printf("Keine passenden Dateien gefunden.\n"),1;
771 if (flags&GREP_I) rexpr=lower_case(rexpr);
772 if (flags&GREP_F)
773 {
Zesstraefad7be2018-11-06 23:18:30 +0100774 if (file_size("/players/"+getuid()+"/grep.out")==FSIZE_DIR
775 || !MAY_WRITE("/players/"+getuid()+"/grep.out"))
MG Mud User88f12472016-06-24 23:31:02 +0200776 return printf("grep: Datei /players/%s/grep.out kann nicht "
Zesstraefad7be2018-11-06 23:18:30 +0100777 "geschrieben werden.\n",getuid()),1;
MG Mud User88f12472016-06-24 23:31:02 +0200778 else
779 write_file("/players/"+getuid()+"/grep.out",
780 "Ausgabe von \"grep " + _unparsed_args() + "\":\n");
781 }
782 asynchron(args,#'grep_file,rexpr,flags,0);
783 return 1;
784}