various work on readtxt2.pas
authorplugwash <plugwash@p10link.net>
Sat, 23 Feb 2013 02:25:59 +0000 (02:25 +0000)
committerplugwash <plugwash@p10link.net>
Sat, 23 Feb 2013 02:25:59 +0000 (02:25 +0000)
fix issue with files where a line with a unix line ending followed a line with a mac line ending
add support for applications to specify that only a single line ending type is a valid line ending
expand testreadtxt2.dpr

git-svn-id: file:///svnroot/lcore/trunk@124 b1de8a11-f9be-4011-bde0-cc7ace90066a

lserial.pas
readtxt2.pas
testreadtxt2.dpr

index cee472708da49cb622129a3eabd022ccb3f676a4..4f13fce4c51208cde9738df7a9f98d760de164db 100755 (executable)
@@ -1,71 +1,71 @@
-{$mode delphi}
-unit lserial;
-interface
-uses 
-  lcore;
-  
-type
-  tlserial=class(tlasio)
-  public 
-    device: string;
-       baudrate: longint;
-    procedure open;
-  end;
-  
-  
-implementation
-uses
-  baseunix,
-  unix,
-  unixutil,
-  termio, // despite the name the fpc termio unit seems to be an interface to termios
-  sysutils;
-procedure tlserial.open;
-var
-  fd : longint;
-  config : termios;
-  baudrateos : longint;
-begin
-  fd := fpopen(device,O_RDWR or O_NOCTTY or O_NONBLOCK);
-  
-  if isatty(fd)=0 then begin
-    writeln('not a tty');
-    halt(1);
-  end;
-
-  fillchar(config,sizeof(config),#0);
-  config.c_cflag := CLOCAL or CREAD;
-  cfmakeraw(config);
-  case baudrate of
-    50:     baudrateos := B50;
-       75:     baudrateos := B75;
-       110:    baudrateos := B110;
-       134:    baudrateos := B134;
-       150:    baudrateos := B150;
-       200:    baudrateos := B200;
-       300:    baudrateos := B300;
-       600:    baudrateos := B600;
-       1200:   baudrateos := B1200;
-       1800:   baudrateos := B1800;
-       2400:   baudrateos := B2400;
-       4800:   baudrateos := B4800;
-       9600:   baudrateos := B9600;
-       19200:  baudrateos := B19200;
-       38400:  baudrateos := B38400;
-       57600:  baudrateos := B57600;
-       115200: baudrateos := B115200;
-       230400: baudrateos := B230400; 
-       else raise exception.create('unrecognised baudrate');
-  end;
-  cfsetispeed(config,baudrateos);
-  cfsetospeed(config,baudrateos);
-  config.c_cc[VMIN]  := 1;
-  config.c_cc[VTIME] := 0;
-  if   tcsetattr(fd,TCSAFLUSH,config) <0 then begin
-    writeln('could not set termios attributes');
-    halt(3);
-  end;
-  dup(fd);
-  closehandles := true;
-end;
-end.
+{$mode delphi}\r
+unit lserial;\r
+interface\r
+uses \r
+  lcore;\r
+  \r
+type\r
+  tlserial=class(tlasio)\r
+  public \r
+    device: string;\r
+       baudrate: longint;\r
+    procedure open;\r
+  end;\r
+  \r
+  \r
+implementation\r
+uses\r
+  baseunix,\r
+  unix,\r
+  unixutil,\r
+  termio, // despite the name the fpc termio unit seems to be an interface to termios\r
+  sysutils;\r
+procedure tlserial.open;\r
+var\r
+  fd : longint;\r
+  config : termios;\r
+  baudrateos : longint;\r
+begin\r
+  fd := fpopen(device,O_RDWR or O_NOCTTY or O_NONBLOCK);\r
+  \r
+  if isatty(fd)=0 then begin\r
+    writeln('not a tty');\r
+    halt(1);\r
+  end;\r
+\r
+  fillchar(config,sizeof(config),#0);\r
+  config.c_cflag := CLOCAL or CREAD;\r
+  cfmakeraw(config);\r
+  case baudrate of\r
+    50:     baudrateos := B50;\r
+       75:     baudrateos := B75;\r
+       110:    baudrateos := B110;\r
+       134:    baudrateos := B134;\r
+       150:    baudrateos := B150;\r
+       200:    baudrateos := B200;\r
+       300:    baudrateos := B300;\r
+       600:    baudrateos := B600;\r
+       1200:   baudrateos := B1200;\r
+       1800:   baudrateos := B1800;\r
+       2400:   baudrateos := B2400;\r
+       4800:   baudrateos := B4800;\r
+       9600:   baudrateos := B9600;\r
+       19200:  baudrateos := B19200;\r
+       38400:  baudrateos := B38400;\r
+       57600:  baudrateos := B57600;\r
+       115200: baudrateos := B115200;\r
+       230400: baudrateos := B230400; \r
+       else raise exception.create('unrecognised baudrate');\r
+  end;\r
+  cfsetispeed(config,baudrateos);\r
+  cfsetospeed(config,baudrateos);\r
+  config.c_cc[VMIN]  := 1;\r
+  config.c_cc[VTIME] := 0;\r
+  if   tcsetattr(fd,TCSAFLUSH,config) <0 then begin\r
+    writeln('could not set termios attributes');\r
+    halt(3);\r
+  end;\r
+  dup(fd);\r
+  closehandles := true;\r
+end;\r
+end.\r
index 1888c5b21e837b81c30780a7f3b11f10218faee0..2c269a78adab9df1fb50743ced738ce31489990a 100644 (file)
@@ -22,31 +22,34 @@ uses
 const\r
   bufsize=4096;\r
   eoltype_none=0;\r
+  eoltype_any=0;\r
   eoltype_cr=1;\r
   eoltype_lf=2;\r
   eoltype_crlf=3;\r
 \r
 type\r
   treadtxt=class(tobject)\r
+  private\r
+    buf:array[0..bufsize-1] of byte;\r
+    numread:integer;\r
+    bufpointer:integer;\r
+    currenteol,preveol:integer;\r
+    fileeof,reachedeof:boolean;\r
+    fdetectedeol:integer;\r
+    procedure checkandread;\r
   public\r
     sourcestream:tstream;\r
     destroysourcestream:boolean;\r
+    allowedeol:integer;\r
     constructor create(asourcestream: tstream; adestroysourcestream:boolean);\r
     constructor createf(filename : string);\r
 \r
     function readline:ansistring;\r
     function eof:boolean;\r
     destructor destroy; override;\r
-  private\r
-    buf:array[0..bufsize-1] of byte;\r
-    numread:integer;\r
-    bufpointer:integer;\r
-    currenteol,preveol:integer;\r
-    fileeof,reachedeof:boolean;\r
-    eoltype:integer;\r
-    procedure checkandread;\r
+    property detectedeol : integer read fdetectedeol;\r
   end;\r
-\r
+  \r
 implementation\r
 \r
 constructor treadtxt.create(asourcestream: tstream; adestroysourcestream:boolean);\r
@@ -78,21 +81,51 @@ end;
 function treadtxt.readline;\r
 var\r
   a,b,c,d:integer;\r
+  prevchar : integer;\r
+  trimchar : boolean;\r
 begin\r
-\r
+  prevchar := 0;\r
   result := '';\r
   repeat\r
     checkandread;\r
     b := numread-1;\r
-\r
+    trimchar := false;\r
     {core search loop begin}\r
     d := -1;\r
     for a := bufpointer to b do begin\r
       c := buf[a];\r
-      if (c = 10) or (c = 13) then begin\r
-         d := a;\r
-         break;\r
+      //check if the character can possiblly be a line ending before getting\r
+      //into the more complex checks that depend on eol type\r
+      if (c = 10) or (c = 13) then case allowedeol of\r
+        eoltype_any: begin\r
+          d := a;\r
+          break;\r
+        end;\r
+        eoltype_cr: begin\r
+          if (c = 13) then begin\r
+            d := a;\r
+            break;\r
+          end;\r
+        end;\r
+        eoltype_lf: begin\r
+          if (c = 10) then begin\r
+            d := a;\r
+            break;\r
+          end;\r
+        end;\r
+        eoltype_crlf: begin\r
+          if (c = 10) and (prevchar= 13) then begin\r
+            d := a;\r
+            trimchar := true;\r
+            break;\r
+          end;\r
+          prevchar := c;\r
+        end;\r
+        else begin\r
+          raise exception.create('undefined eol type set');\r
+        end;\r
       end;\r
+      prevchar := c;\r
     end;\r
     {core search loop end}\r
     \r
@@ -114,18 +147,24 @@ begin
       currenteol := buf[d];\r
 \r
       {end of line before end of buffer}\r
-      if (currenteol = 10) and (preveol = 13) then begin\r
+      if (currenteol = 10) and (preveol = 13) and (bufpointer = d) then begin\r
         {it's the second EOL char of a DOS line ending, don't cause a line}\r
         bufpointer := d+1;\r
-        eoltype := eoltype_crlf;\r
+        fdetectedeol := eoltype_crlf;\r
       end else begin\r
-        if eoltype = eoltype_none then begin\r
-          if (currenteol = 10) then eoltype := eoltype_lf else eoltype := eoltype_cr;\r
+        if fdetectedeol = eoltype_none then begin\r
+          if (currenteol = 10) then fdetectedeol := eoltype_lf else fdetectedeol := eoltype_cr;\r
         end;  \r
         b := d-bufpointer;\r
-        setlength(result,c+b);\r
-        move(buf[bufpointer],result[c+1],b);\r
-        bufpointer := d+1;\r
+        if trimchar then begin\r
+          setlength(result,c+b-1);\r
+          move(buf[bufpointer],result[c+1],b-1);\r
+          bufpointer := d+1;\r
+        end else begin\r
+          setlength(result,c+b);\r
+          move(buf[bufpointer],result[c+1],b);\r
+          bufpointer := d+1;\r
+        end;\r
 \r
         {EOF check}\r
         if fileeof then begin\r
index 1e1d69acde3f11cb0a04d9213094372f9807c1f2..3e7d0df91fd6cf7f7eccf22a002ee9a0188953b8 100644 (file)
@@ -23,14 +23,44 @@ begin
   writestring(f,'DOS'#13#10);\r
   writestring(f,'UNIX'#10);\r
   writestring(f,'MAC'#13);\r
+  writestring(f,'UNIX'#10);\r
   writestring(f,'NONE');\r
   closefile(f);\r
+  \r
+  writeln('reading test file in default mode (all line endings treated as line endings)');\r
   t := treadtxt.createf('mixed.txt');\r
   if t.readline = 'DOS' then writeln('DOS success') else writeln('DOS fail');\r
   if t.readline = 'UNIX' then writeln('UNIX success') else writeln('UNIX fail');\r
   if t.readline = 'MAC' then writeln('MAC success') else writeln('MAC fail');\r
+  if t.readline = 'UNIX' then writeln('UNIX success') else writeln('UNIX fail');\r
   if t.readline = 'NONE' then writeln('NONE success') else writeln('NONE fail');\r
   t.destroy;\r
+  \r
+  writeln('reading test file with only CR treated as a line ending');\r
+  t := treadtxt.createf('mixed.txt');\r
+  t.allowedeol := eoltype_cr;\r
+  if t.readline = 'DOS' then writeln('DOS success') else writeln('DOS fail');\r
+  if t.readline = #10'UNIX'#10'MAC' then writeln('LF+UNIX+LF+MAC success') else writeln('LF+UNIX+LF+MAC fail');\r
+  if t.readline = 'UNIX'#10'NONE' then writeln('UNIX+LF+NONE success') else writeln('UNIX+LF+NONE fail');\r
+  t.destroy;\r
+\r
+  writeln('reading test file with only LF treated as a line ending');\r
+  t := treadtxt.createf('mixed.txt');\r
+  t.allowedeol := eoltype_lf;\r
+  if t.readline = 'DOS'#13 then writeln('DOS+CR success') else writeln('DOS+CR fail');\r
+  if t.readline = 'UNIX' then writeln('UNIX success') else writeln('UNIX fail');\r
+  if t.readline = 'MAC'#13'UNIX' then writeln('MAC+CR+UNIX success') else writeln('MAC+CR+UNIX fail');\r
+  if t.readline = 'NONE' then writeln('NONE success') else writeln('NONE fail');\r
+  t.destroy;\r
+\r
+  writeln('reading test file with only CRLF treated as a line ending');\r
+  t := treadtxt.createf('mixed.txt');\r
+  t.allowedeol := eoltype_crlf;\r
+  if t.readline = 'DOS' then writeln('DOS success') else writeln('DOS fail');\r
+  if t.readline = 'UNIX'#10'MAC'#13'UNIX'#10'NONE' then writeln('UNIX+LF+MAC+CR+UNIX+LF+NONE success') else writeln('UNIX+LF+MAC+CR+UNIX+LF+NONE fail');\r
+  t.destroy;\r
+\r
+  \r
   {$ifdef win32}\r
     //make things a little easier to test in the delphi GUI\r
     readln;\r