grep neu implementiert.

Die bisherige Methode des portionsweisen Einlesens
klappt nur fuer ASCII-Dateien.
Daher erst alles einlesen, dann konvertieren und
dann suchen. Vereinfacht auch den Code deutlich...

Ausserdem die Behandlung von -l gefixt: dieses gab
bislang den Dateiinhalt aus. Da aber das
Standardverhalten schon die Ausgabe von Dateinamen
ist, ist mir nicht klar, was -l eigentlich tun soll.

Change-Id: I4684e5c5f428b7a9d91568e7dd578aa655a8e03e
diff --git a/std/shells/magier/fileview.c b/std/shells/magier/fileview.c
index f325896..58d7dfc 100644
--- a/std/shells/magier/fileview.c
+++ b/std/shells/magier/fileview.c
@@ -14,6 +14,7 @@
 #include <daemon/mand.h>
 #include <udp.h>
 #include <files.h>
+#include <rtlimits.h>
 
 #define NEED_PROTOTYPES
 #include <magier.h>
@@ -575,9 +576,7 @@
 
 private int grep_file(mixed filedata, string rexpr, int flags)
 {
-  string fullname,data,carry,*lines,*lines_orig,*tmp,*result;
-  int ptr,count,i,nol,match,index;
-  fullname=filedata[FULLNAME];
+  string fullname=filedata[FULLNAME];
   if ((flags&GREP_F)&&fullname=="/players/"+getuid()+"/grep.out")
   {
     write_file("/players/"+getuid()+"/grep.out",
@@ -593,79 +592,75 @@
   }
   if (!MAY_READ(fullname))
     return ERROR(NO_READ,fullname,RET_FAIL);
-  carry=""; result=({});
+
+  // Bei case-insensitiver Suche das Pattern in Kleinschreibung wandeln
   if (flags&GREP_I)
     rexpr=lower_case(rexpr);
-  do
+
+  // Portionsweise das komplette File einlesen.
+  int maxlen = query_limits()[LIMIT_BYTE];
+  int ptr;
+  bytes read_buffer;
+  bytes data = b"";
+  while (sizeof(read_buffer = read_bytes(fullname, ptr, maxlen)))
   {
-    data=to_text(read_bytes(fullname,ptr,MAXLEN)||"", "UTF-8");
-    ptr+=MAXLEN;
-    lines=explode(carry+data,"\n");
-    switch(sizeof(lines))
-    {
-      case 0: continue;
-      case 1:
-        carry="";
-        break;
-      default:
-        carry=lines[<1];
-        lines=lines[0..<2];
-        break;
-    }
-    lines_orig=lines;
-    if (flags&GREP_I)
-      lines=map(lines,#'lower_case);
-    nol=sizeof(lines);
-    for (i=0;i<nol;i++)
-    {
-      match=sizeof(regexp(lines[i..i],rexpr));
-      if (flags&GREP_V) match=!match;
-      if (match)
-      {
-        if (!(flags&GREP_C))
-        {
-          if (flags&GREP_N)
-            result+=({ sprintf("%4d %s",index+i+1,lines_orig[i])});
-          else
-            result+=lines_orig[i..i];
-        }
-        count++;
-      }
-    }
-    index+=nol;
+    data += read_buffer;
+    ptr += sizeof(read_buffer);
+    // die Schleifenbedingung erkennt zwar auch, wenn das File vollstaendig
+    // ist, aber wir koennen den Speicherzugriff auch einsparen und schauen,
+    // ob wir schon alles haben.
+    if (ptr >= filedata[FILESIZE])
+      break;
   }
-  while(sizeof(data)==MAXLEN);
-  if (carry!="")
+  // In string konvertieren, wir gehen davon aus, das File ist UTF8-kodiert.
+  string text = to_text(data, "UTF-8");
+  string *lines = explode(text, "\n");
+  int count; // Anzahl Zeilen mit Treffern
+  <string|string*> result = ({}); // zutreffende Zeilen
+  int linecount = 1;
+  foreach(string line: lines)
   {
-    if (flags&GREP_I) carry=lower_case(carry);
-    match=sizeof(regexp(({ carry }),rexpr));
-    if (flags&GREP_V) match=!match;
+    string orig_line = line;
+    // Suche case-insensitive?
+    if (flags&GREP_I)
+      line = lower_case(line);
+    int match = regmatch(line, rexpr) != 0;
+    if (flags&GREP_V) match = !match; // Match ggf. invertieren
     if (match)
     {
-      if(!(flags&GREP_C))
+      // Ausgeben oder nicht?
+      if (!(flags&GREP_C))
       {
-        if(flags&GREP_N)
-           result+=({ sprintf("%4d %s",index+1,carry) });
+        // Mit Zeilennummer?
+        if (flags&GREP_N)
+          result+=({ sprintf("%4d %s", linecount, orig_line)});
         else
-           result+=({carry});
+          result+=({orig_line});
       }
-      count++;
+      ++count;
     }
+    ++linecount;
   }
-  carry="";
+
   if (count)
   {
-    if (flags&GREP_L) carry=sprintf("%s\n",fullname);
-    else if (flags&GREP_H) data="";
-    else data=sprintf(" %s:",fullname);
-    if (flags&GREP_C) carry=sprintf("%s %d passende Zeile%s.\n",data,count,
-                             (count==1?"":"n"));
+    // Bei -h werden die Dateinamen unterdrueckt.
+    if (flags&GREP_H)
+      fullname="";
     else
-      carry=(data+"\n"+implode(result,"\n")+"\n");
+      fullname=sprintf("%s ",fullname);
+
+    if (flags&GREP_C)
+      result=sprintf("%s%d passende Zeile%s.\n",fullname, count,
+                           (count==1?"":"n"));
+    else
+      result = ( (sizeof(fullname) ? fullname + "\n" : "")
+                + implode(result,"\n") + "\n");
   }
+
   if (flags&GREP_F)
-    return write_file("/players/"+getuid()+"/grep.out",carry);
-  write(carry);
+    return write_file("/players/"+getuid()+"/grep.out",result);
+  write(result);
   return RET_OK;
 }