#FEATURE by cg
authorClaus Gittinger <cg@exept.de>
Tue, 25 Feb 2020 14:06:32 +0100
changeset 25296 c8af45a8476a
parent 25295 7067a6ee0f20
child 25297 2de626cc2673
#FEATURE by cg class: CharacterArray class added: #readSmalltalkStringFrom:keepCRs:onError: comment/format in: #readSmalltalkStringFrom:onError: changed: #readSmalltalkStringWithCRsFrom:onError:
CharacterArray.st
--- a/CharacterArray.st	Tue Feb 25 12:30:20 2020 +0100
+++ b/CharacterArray.st	Tue Feb 25 14:06:32 2020 +0100
@@ -260,18 +260,25 @@
     ^ self basicNew:0
 !
 
-readSmalltalkStringFrom:aStreamOrString onError:exceptionBlock
+readSmalltalkStringFrom:aStreamOrString keepCRs:keepCRs onError:exceptionBlock
     "read & return the next String from the (character-)stream aStream;
      skipping all whitespace first; return the value of exceptionBlock,
      if no string can be read. The sequence of characters as read from the
-     stream must be one as stored via storeOn: or storeString."
-
-    |str collected char|
+     stream must be one as stored via storeOn: or storeString.
+     If keepCRs is true, CRLF is kept as is.
+     A variant of this code is also found in the Scanner class (libcomp);
+     however, libcomp is optional, whereas this is always present,
+     and string reading is needed for resource file and config file parsing (sigh)"
+
+    |str collected char withCEscapes|
 
     str := aStreamOrString readStream.
     "skip whiteSpace"
     str skipSeparators.
 
+    (withCEscapes := (str peekOrNil == $c)) ifTrue:[
+        str next.
+    ].
     (str peekOrNil == $') ifTrue:[
         str next.
         collected := self writeStream.
@@ -285,9 +292,31 @@
                 "eat doubled quote"
                 str next.
             ].
-            ((char ~~ Character return) or:[str peekOrNil ~~ Character lf]) ifTrue:[
+            (withCEscapes and:[char == $\]) ifTrue:[
+                char := str nextOrNil ? char.
+                char == $r ifTrue:[
+                    char := Character return
+                ] ifFalse:[
+                    char == $n ifTrue:[
+                        char := Character linefeed
+                    ] ifFalse:[
+                        char == $b ifTrue:[
+                            char := Character backspace
+                        ] ifFalse:[
+                            char == $t ifTrue:[
+                                char := Character tab
+                            ]
+                        ]
+                    ]
+                ].
+            ].
+            keepCRs ifTrue:[
+                collected nextPut:char.
+            ] ifFalse:[
                 "compress CRLF to LF, but keep a single CR"
-                collected nextPut:char.
+                ((char ~~ Character return) or:[str peekOrNil ~~ Character lf]) ifTrue:[
+                    collected nextPut:char.
+                ]
             ].
         ].
         "if we come here, we reached the end without finding a closing $'"
@@ -299,6 +328,30 @@
      String readSmalltalkStringFrom:('''hello '''' world''' readStream) onError:[self halt]
      String readSmalltalkStringFrom:('1 ''hello'' ' readStream) onError:[self halt]
      String readSmalltalkStringFrom:('1 ''hello'' ' readStream) onError:['foobar']
+     String readSmalltalkStringFrom:('''hello\nworld''' readStream) onError:[self halt. 'foobar'] 
+
+     String readSmalltalkStringFrom:('''hello\nworld''' readStream) keepCRs:false onError:[self halt. 'foobar']   
+     String readSmalltalkStringFrom:('c''hello\nworld''' readStream) keepCRs:false onError:[self halt. 'foobar'] 
+    "
+
+    "Created: / 05-07-2006 / 16:41:04 / cg"
+    "Modified: / 06-10-2006 / 14:05:32 / cg"
+    "Modified (comment): / 02-08-2019 / 10:10:46 / Stefan Vogel"
+!
+
+readSmalltalkStringFrom:aStreamOrString onError:exceptionBlock
+    "read & return the next String from the (character-)stream aStream;
+     skipping all whitespace first; return the value of exceptionBlock,
+     if no string can be read. The sequence of characters as read from the
+     stream must be one as stored via storeOn: or storeString."
+
+    ^ self readSmalltalkStringFrom:aStreamOrString keepCRs:false withCEscapes:false onError:exceptionBlock
+
+    "
+     String readSmalltalkStringFrom:('''hello world''' readStream) onError:[self halt]
+     String readSmalltalkStringFrom:('''hello '''' world''' readStream) onError:[self halt]
+     String readSmalltalkStringFrom:('1 ''hello'' ' readStream) onError:[self halt]
+     String readSmalltalkStringFrom:('1 ''hello'' ' readStream) onError:['foobar']
     "
 
     "Created: / 05-07-2006 / 16:41:04 / cg"
@@ -314,33 +367,10 @@
 
      Different from #readSmalltalStringFrom:onError: we keep CRLF as is."
 
-    |str collected char|
-
-    str := aStreamOrString readStream.
-    "skip whiteSpace"
-    str skipSeparators.
-
-    (str peekOrNil == $') ifTrue:[
-        str next.
-        collected := self writeStream.
-        [(char := str nextOrNil) notNil] whileTrue:[
-            char == $' ifTrue:[
-                "/ look for another quote
-                str peekOrNil ~~ $' ifTrue:[
-                    "end of string reached"
-                    ^ collected contents.
-                ].
-                "eat doubled quote"
-                str next.
-            ].
-            collected nextPut:char.
-        ].
-        "if we come here, we reached the end without finding a closing $'"
-    ].
-    ^ exceptionBlock value
-
-    "
-     String readSmalltalkStringWithCRsFrom:('''hello world''' readStream) onError:[self halt]
+    ^ self readSmalltalkStringFrom:aStreamOrString keepCRs:true onError:exceptionBlock
+
+    "
+     String readSmalltalkStringWithCRsFrom:('''hello world''' readStream) onError:[self halt]  
      String readSmalltalkStringWithCRsFrom:('''hello '''' world''' readStream) onError:[self halt]
      String readSmalltalkStringWithCRsFrom:('1 ''hello'' ' readStream) onError:[self halt]
      String readSmalltalkStringWithCRsFrom:('1 ''hello'' ' readStream) onError:['foobar']