blob: f96d6e3aa3a5571b563906f95faaf15eb5ebe236 [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 {
Zesstraefad7be2018-11-06 23:18:30 +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{
414 mixed *args;
415 int i, flags;
416 string *tmp, *tmp2;
417
418 cmdline=_unparsed_args();
419 args=parseargs(cmdline,&flags,MAN_OPTS,0);
420
421 if (flags==-1 ||
422 (sizeof(args)!=1 &&
423 (sizeof(args)<2 || sizeof(args[1])>1 || !(i=to_int(args[1])))))
424 return USAGE("man [-" MAN_OPTS "] <hilfeseite>");
425 tmp=explode(args[0],"/");
426
427 if (oldman_result && sizeof(tmp)==1 && sizeof(args)==1 &&
428 sizeof(tmp[0])==1 && (i=to_int(tmp[0])) && member(oldman_result,i)) {
429 tmp=({oldman_result[i,0],oldman_result[i,1]});
430 i=0;
431 }
432 else if (!(flags&(MAN_M|MAN_R))&&sizeof(tmp)>1)
433 {
434 if (file_size(MAND_DOCDIR+args[0])>=0)
435 tmp=({tmp[<1],args[0]});
436 else
437 tmp=({});
438 }
439 else
440 {
441 if (flags&MAN_R)
442 {
443 flags&=(~MAN_M);
444 if (catch(regexp(({""}),args[0]))||
445 !regexp(({""}),args[0]))
446 return printf("man: Ungueltiger Ausdruck in Maske.\n"),1;
447 }
448 tmp=(string *)call_other(MAND,"locate",args[0],flags&(MAN_M|MAN_R));
449 }
450
451 oldman_result=(mapping)0;
452 if(i && sizeof(tmp)>2 && sizeof(tmp)>=(i<<1))
453 tmp=tmp[((i<<1)-2)..((i<<1)-1)];
454 switch(sizeof(tmp))
455 {
456 case 0:
457 printf("Keine Hilfeseite gefunden fuer '%s'.\n",args[0]);
458 break;
459 case 2:
460 /*
461 if (flags&MAN_I)
462 {
463 // BRANCH TO MANUALD
464 return 1;
465 }
466 */
467 printf("Folgende Hilfeseite wurde gefunden: %s\n",tmp[1]);
468 More(MAND_DOCDIR+tmp[1],1);
469 return 1;
470 default:
471 i=sizeof(tmp)>>1;
472 tmp2=allocate(i);
473 oldman_result=m_allocate(i,2);
474 while(i)
475 {
476 tmp2[(i-1)]=sprintf("%d: ",i)+tmp[(i<<1)-2];
Zesstraefad7be2018-11-06 23:18:30 +0100477 oldman_result[i,0]=tmp[(i<<1)-2];
478 oldman_result[i,1]=tmp[(i<<1)-1];
MG Mud User88f12472016-06-24 23:31:02 +0200479 i--;
480 }
481 printf("Es wurden folgende potentiell passenden Seiten gefunden:\n"
482 "%'-'78.78s\n%s%'-'78.78s\n","",
483 break_string(implode(tmp2," "),78),"");
484 break;
485 }
486 return 1;
487}
488
489// ########
490//############################### RMAN ##################################
491// ########
492
493static int _rman(string str)
494{
495 int flags;
496 string *args;
497
498 str=_unparsed_args();
499 args=parseargs(str,&flags,"",0);
500 if (flags==-1||sizeof(args)!=2)
501 return USAGE("rman <hilfeseite> <mudname>");
502 write("man: " +
503 (string)call_other(UDP_CMD_DIR+"man","send_request",args[1],args[0]));
504 return 1;
505}
506
507
508// #############
509//############################# SHOWPROPS ###############################
510// #############
511
512//
513// _showprops: Zeigt Properties zu einem Objekt an
514//
515
516static int _showprops(string str)
517{
518 int i;
519 string *list, ausgabe;
520
521 if (str) {
522 if (str[0]!='/') str="/"+str;
523 if (str[0..4]!="/std/")
524 {
525 printf("showprops: Es koennen nur Properties von Objekten "
526 "aus /std/ angezeigt werden.\n");
527 return 1;
528 }
529 if (str[<1]=='.') str+="c";
530 if (str[<2..<1]!=".c") str+=".c";
531 if (file_size(str)<0)
532 {
533 printf("showprops: %s: Es gibt kein Objekt diesen Namens.\n",str[0..<3]);
534 return 1;
535 }
Zesstraefad7be2018-11-06 23:18:30 +0100536 if (catch(load_object(str)))
MG Mud User88f12472016-06-24 23:31:02 +0200537 {
538 printf("showprops: %s: Datei konnte nicht geladen werden.\n",str);
539 return 1;
540 }
541 }
542 if (!str || !find_object(str)) {
543 notify_fail("Welche Properties moechtest Du sehen?"
544 " Bsp.: <showprops /std/npc>\n");
545 return 0;
546 }
547 list=inherit_list(find_object(str));
MG Mud User88f12472016-06-24 23:31:02 +0200548 list=map(list,(: return $1[5..<2]+"h"; :));
549 list+=map(list,(: return explode($1,"/")[<1]; :));
550 list=map(m_indices(mkmapping(list)),(: return "/sys/"+$1; :));
551 list=filter(list,(: return file_size($1)>0; :));
MG Mud User88f12472016-06-24 23:31:02 +0200552 list=sort_array(list, #'<);
553 ausgabe="";
554 for (i=sizeof(list);i--;)
555 {
MG Mud User88f12472016-06-24 23:31:02 +0200556 str=implode(filter(explode(read_file(list[i]),"\n"),
557 (: return $1[0..9]=="#define P_";:)),"\n");
MG Mud User88f12472016-06-24 23:31:02 +0200558 if (str!="") ausgabe+=sprintf("%s\n%s\n\n", list[i], str);
559 }
560 if (ausgabe!="")
561 More(ausgabe);
562 else
563 printf("Keine Property-Definitionen zu diesem Objekt gefunden!\n");
564 return 1;
565}
566
567// ########
568//############################### GREP ###################################
569// ########
570
MG Mud User88f12472016-06-24 23:31:02 +0200571//
572// grep_file: Datei greppen
573// rexpr: Regular Expression
574// flags: Flags
575//
576
577private int grep_file(mixed filedata, string rexpr, int flags)
578{
Zesstrac70bf582019-11-26 00:43:17 +0100579 string fullname=filedata[FULLNAME];
MG Mud User88f12472016-06-24 23:31:02 +0200580 if ((flags&GREP_F)&&fullname=="/players/"+getuid()+"/grep.out")
Zesstraefad7be2018-11-06 23:18:30 +0100581 {
582 write_file("/players/"+getuid()+"/grep.out",
583 "Uebergehe grep.out ...\n");
584 return RET_FAIL;
MG Mud User88f12472016-06-24 23:31:02 +0200585 }
586 switch(filedata[FILESIZE])
587 {
Zesstraefad7be2018-11-06 23:18:30 +0100588 case FSIZE_DIR: return RET_FAIL;
589 case FSIZE_NOFILE: return ERROR(DOESNT_EXIST,fullname,RET_FAIL);
MG Mud User88f12472016-06-24 23:31:02 +0200590 case 0: return RET_FAIL;
591 default: break;
592 }
Zesstraefad7be2018-11-06 23:18:30 +0100593 if (!MAY_READ(fullname))
594 return ERROR(NO_READ,fullname,RET_FAIL);
Zesstrac70bf582019-11-26 00:43:17 +0100595
596 // Bei case-insensitiver Suche das Pattern in Kleinschreibung wandeln
MG Mud User88f12472016-06-24 23:31:02 +0200597 if (flags&GREP_I)
598 rexpr=lower_case(rexpr);
Zesstrac70bf582019-11-26 00:43:17 +0100599
600 // Portionsweise das komplette File einlesen.
601 int maxlen = query_limits()[LIMIT_BYTE];
602 int ptr;
603 bytes read_buffer;
604 bytes data = b"";
605 while (sizeof(read_buffer = read_bytes(fullname, ptr, maxlen)))
MG Mud User88f12472016-06-24 23:31:02 +0200606 {
Zesstrac70bf582019-11-26 00:43:17 +0100607 data += read_buffer;
608 ptr += sizeof(read_buffer);
609 // die Schleifenbedingung erkennt zwar auch, wenn das File vollstaendig
610 // ist, aber wir koennen den Speicherzugriff auch einsparen und schauen,
611 // ob wir schon alles haben.
612 if (ptr >= filedata[FILESIZE])
613 break;
MG Mud User88f12472016-06-24 23:31:02 +0200614 }
Zesstrac70bf582019-11-26 00:43:17 +0100615 // In string konvertieren, wir gehen davon aus, das File ist UTF8-kodiert.
616 string text = to_text(data, "UTF-8");
617 string *lines = explode(text, "\n");
618 int count; // Anzahl Zeilen mit Treffern
619 <string|string*> result = ({}); // zutreffende Zeilen
620 int linecount = 1;
621 foreach(string line: lines)
MG Mud User88f12472016-06-24 23:31:02 +0200622 {
Zesstrac70bf582019-11-26 00:43:17 +0100623 string orig_line = line;
624 // Suche case-insensitive?
625 if (flags&GREP_I)
626 line = lower_case(line);
627 int match = regmatch(line, rexpr) != 0;
628 if (flags&GREP_V) match = !match; // Match ggf. invertieren
MG Mud User88f12472016-06-24 23:31:02 +0200629 if (match)
630 {
Zesstrac70bf582019-11-26 00:43:17 +0100631 // Ausgeben oder nicht?
632 if (!(flags&GREP_C))
MG Mud User88f12472016-06-24 23:31:02 +0200633 {
Zesstrac70bf582019-11-26 00:43:17 +0100634 // Mit Zeilennummer?
635 if (flags&GREP_N)
636 result+=({ sprintf("%4d %s", linecount, orig_line)});
MG Mud User88f12472016-06-24 23:31:02 +0200637 else
Zesstrac70bf582019-11-26 00:43:17 +0100638 result+=({orig_line});
MG Mud User88f12472016-06-24 23:31:02 +0200639 }
Zesstrac70bf582019-11-26 00:43:17 +0100640 ++count;
MG Mud User88f12472016-06-24 23:31:02 +0200641 }
Zesstrac70bf582019-11-26 00:43:17 +0100642 ++linecount;
MG Mud User88f12472016-06-24 23:31:02 +0200643 }
Zesstrac70bf582019-11-26 00:43:17 +0100644
MG Mud User88f12472016-06-24 23:31:02 +0200645 if (count)
646 {
Zesstrac70bf582019-11-26 00:43:17 +0100647 // Bei -h werden die Dateinamen unterdrueckt.
648 if (flags&GREP_H)
649 fullname="";
MG Mud User88f12472016-06-24 23:31:02 +0200650 else
Zesstrac70bf582019-11-26 00:43:17 +0100651 fullname=sprintf("%s ",fullname);
652
653 if (flags&GREP_C)
654 result=sprintf("%s%d passende Zeile%s.\n",fullname, count,
655 (count==1?"":"n"));
656 else
657 result = ( (sizeof(fullname) ? fullname + "\n" : "")
658 + implode(result,"\n") + "\n");
Zesstrac70bf582019-11-26 00:43:17 +0100659
Zesstra77c0bf22020-01-07 22:27:27 +0100660 // Ergebnis ausgeben in File oder an Magier
661 if (flags&GREP_F)
662 return write_file("/players/"+getuid()+"/grep.out",result);
663 write(result);
664 }
MG Mud User88f12472016-06-24 23:31:02 +0200665 return RET_OK;
666}
667
668static int _grep(string cmdline)
669{
670 string rexpr,mask;
671 mixed *args;
672 int flags;
673 cmdline=_unparsed_args();
674 args=parseargs(cmdline,&flags,GREP_OPTS,0);
675 if ((flags==-1)||!sizeof(args))
676 return USAGE("grep [-" GREP_OPTS
677 "] <regexp> <datei/verz> [<datei2> ... ] [<maske>]");
678 rexpr=args[0];
679 if (catch(regexp(({""}),rexpr))||!regexp(({""}),rexpr))
680 return printf("grep: Ungueltiger Suchausdruck: %s\n",rexpr) ,1;
Zesstracc3f2502018-11-14 23:46:47 +0100681 args=(sizeof(args)>1 ? args[1..] : ({}) );
MG Mud User88f12472016-06-24 23:31:02 +0200682 if (flags&GREP_M)
683 {
684 mask=args[<1];
Zesstracc3f2502018-11-14 23:46:47 +0100685 if (sizeof(args) > 2)
686 args = (sizeof(args) > 1 ? args[0..<2] : ({}) );
MG Mud User88f12472016-06-24 23:31:02 +0200687 }
688 if (!sizeof(args))
689 return USAGE("grep [-" GREP_OPTS
690 "] <regexp> <datei/verz> [<datei2> ... ] [<maske>]");
691 args=map(args,#'to_filename)-({0});
MG Mud User88f12472016-06-24 23:31:02 +0200692 args=file_list(args,MODE_GREP,(flags&GREP_R?1:0),"/",mask);
693 if (!sizeof(args))
694 return printf("Keine passenden Dateien gefunden.\n"),1;
695 if (flags&GREP_I) rexpr=lower_case(rexpr);
696 if (flags&GREP_F)
697 {
Zesstraefad7be2018-11-06 23:18:30 +0100698 if (file_size("/players/"+getuid()+"/grep.out")==FSIZE_DIR
699 || !MAY_WRITE("/players/"+getuid()+"/grep.out"))
MG Mud User88f12472016-06-24 23:31:02 +0200700 return printf("grep: Datei /players/%s/grep.out kann nicht "
Zesstraefad7be2018-11-06 23:18:30 +0100701 "geschrieben werden.\n",getuid()),1;
MG Mud User88f12472016-06-24 23:31:02 +0200702 else
703 write_file("/players/"+getuid()+"/grep.out",
704 "Ausgabe von \"grep " + _unparsed_args() + "\":\n");
705 }
706 asynchron(args,#'grep_file,rexpr,flags,0);
707 return 1;
708}