Read a data from an input Stream line by line in Smalltalk - stream

Is there a way to read from an input line, line by line in Smalltalk?
I found one approach, which is to use "upTo: Character cr."
Is there any other approach?
Or can I read the line as a String?
Thanks in advance.

Here is how
string := 'line one
line two
line three'.
stream := string readStream
Now,
stream nextLine "answers with 'line one'".
stream nextLine "answers with 'line two'".
stream nextLine "answers with 'line three'"
and at this point
stream atEnd "answers with true"
Notice that nextLine consumes the end-of-line without including it in the answer. If the last line doesn't have an end-of-line, then nextLine will stop right at the end.
Notice also that this allows for a loop to read lines while the stream has more data
[stream atEnd] whileFalse: [self doSomethingWith: stream nextLine]
If you want to read again from the beginning:
stream reset
and if you want to get back to a previos position:
stream position: pos
for example
stream nextLine "read first line".
pos2 := stream position "position of the second line".
stream nextLine "read second line".
stream nextLine "read third line".
stream position: pos2 "get back to line 2".
stream nextLine "again, line 2"

Related

SuperCollider Error: Buffer UGen: no buffer data

Working through how to read sound files into a Buffer and then looping it. When I run the script to create a Buffer and read a sound file into it, it succeeds, but when I create a SynthDef using that buffer (the second line of code here), it gives me the error Buffer UGen: no buffer data. It's drawing on the same bufnum, so I'm not sure what's going on.
b = Buffer.read(s, Platform.resourceDir +/+ "sounds/testing.wav");
c= SynthDef(\loopbuffer, {arg start=0, end=10000; Out.ar(0,Pan2.ar(BufRd.ar(1, 0, Phasor.ar(0, BufRateScale.kr(b.bufnum), start, end),0.0)))}).play(s);
Platform.resourceDir ++ "/sounds/testing.wav"
The ++ here means no space is inserted when concatenating.
BufRd.ar(b.numChannels, b.bufNum)
The missing b.bufNum is causing your error. The channels 0 through 3 are reserved for hardware in/outs.

POS Printer Cutter cutting on wrong location

i am trying to Cut paper after every line in VB6 here is the code
Open "LPT1" For Output As #1
Print #1, Chr$(&H1B); "#"; 'Initializes the printer (ESC #)
Print #1, Chr$(&H1B); "d"; Chr$(0); 'Prints and line feeding (ESC d)
Print #1, Chr$(&H1B); "!"; Chr$(17); 'Selects double-height mode
For a = 1 To 5
Print #1, "14-January Invoice 01000"; Chr$(&HA); 'Prints and line feed
Print #1, Chr$(&H1B); "m"; Chr$(&HA); 'Cut Paper
Next
Print #1, Chr$(&H1D); "V"; Chr$(66); Chr$(0);
Close #1
it should be printing a line after then cut the paper but it start cutting paper from the top
any body can help me on this?
update: basically what i want is to make small tags where date and invoice written on it and tag max 1 cm long.
You are performing a partial cut (ESC m) inside of your loop, after every line you are printing. I think you probably want to remove that line:
Print #1, Chr$(&H1B); "m"; Chr$(&HA); 'Cut Paper
After the loop, you then perform a feed-and-cut (partial cut) operation (GS V 66 0) after the loop completes. I think you probably want to keep that line to perform the cut after you've printed.

serial data flow: How to ensure completion

I have a device that sends serial data over a USB to COM port to my program at various speeds and lengths.
Within the data there is a chunk of several thousands bytes that starts and ends with special distinct code ('FDDD' for start, 'FEEE' for end).
Due to the stream's length, occasionally not all data is received in one piece.
What is the recommended way to combine all bytes into one message BEFORE parsing it?
(I took care of the buffer size, but have no control over the serial line quality, and can not use hardware control with USB)
Thanks
One possible way to accomplish this is to have something along these lines:
# variables
# buffer: byte buffer
# buffer_length: maximum number of bytes in the buffer
# new_char: char last read from the UART
# prev_char: second last char read from the UART
# n: index to the buffer
new_char := 0
loop forever:
prev_char := new_char
new_char := receive_from_uart()
# start marker
if prev_char = 0xfd and new_char = 0xdd
# set the index to the beginning of the buffer
n := 0
# end marker
else if prev_char = 0xfe and new_char = 0xee
# the frame is ready, do whatever you need to do with a complete message
# the length of the payload is n-1 bytes
handle_complete_message(buffer, n-1)
# otherwise
else
if n < buffer_length - 1
n := n + 1
buffer[n] := new_char
A few tips/comments:
you do not necessarily need a separate start and end markers (you can the same for both purposes)
if you want to have two-byte markers, it would be easier to have them with the same first byte
you need to make sure the marker combinations do no occur in your data stream
if you use escape codes to avoid the markers in your payload, it is convenient to take care of them in the same code
see HDLC asynchronous framing (simply to encode, simple to decode, takes care of the escaping)
handle_complete_message usually either copies the contents of buffer elsewhere or swaps another buffer instead of buffer if in hurry
if your data frames do not have integrity checking, you should check if the payload length is equal to buffer_length- 1, because then you may have an overflow
After several tests, I came up with the following simple solution to my own question (for c#).
Shown is a minimal simplified solution. Can add length checking, etc.
'Start' and 'End' are string markers of any length.
public void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
SerialPort port = (SerialPort)sender;
inData = port.ReadExisting();
{
if (inData.Contains("start"))
{
//Loop to collect all message parts
while (!inData.Contains("end"))
inData += port.ReadExisting();
//Complete by adding the last data chunk
inData += port.ReadExisting();
}
//Use your collected message
diaplaydata(inData);

Write to middle of text file

I am using Delphi 7.0 and need to be able to write to the middle of a text file. Here is an example of the text file my program creates.
~V
VERS. 2.0: CWLS LOG ASCII STANDARD - VERSION 2.0
WRAP. NO : One line per depth step
~W
STRT.Ft 10000 : Start Depth
STOP.Ft 11995 : Stop Depth
STEP.Ft 5 : Step
... A bunch of data follows.
Now, when I initially write the values to the text file I would like to remember the file position of the STOP value of 11995 in the above example. Now, some time later my data will change and I would like to move to the position of 11995 and write the new stop value. That way I don't need to rewrite everything in the file.
With standard Pascal File I/O you can only read, rewrite or append data in the file.
If you want to change data in a certain position of the file you can use TFileStream:
var
f:TFileStream;
PositionStr:String;
PositionValue:Integer;
begin
f := TFileStream.Create('filename.log',fmOpenReadWrite);
PositionValue := 200000; // new STOP Position
PositionStr := IntToStr(PositionValue);
f.Seek(100,soFromBeginning); // Data will be overwritten from position 100
f.WriteBuffer(PositionStr[1], length(PositionStr));
f.free;
end;

Processing the file problem

in a ruby learning book .I face this code :
f = File.new("a.txt", "r")
while a = f.getc
puts a.chr
f.seek(5, IO::SEEK_CUR)
end
author writes that this code produce every fifth character in a file, but I don't understand why? please explain me line by line.
thanks.
f = File.new("a.txt", "r")
This line opens the file in read mode and keeps the file object(as an I/O(Input/Output) stream) in variable f. (See File#new)
while a = f.getc
getc is a method of class IO which gets one character of the I/O stream at a time and it will give nil, when it meets the end of the I/O stream. So while a = f.getc will loop until the end of file. (See IO#getc)
puts a.chr
f.getc will give the ASCII value of the character and inorder to get the character from the ASCII value, we apply a.chr(See Integer#chr). I think in Ruby 1.9, we will get the character itself as the output of getc, but for earlier versions, we get the ASCII value as the output. The first getc command reads the first character and moves the position of I/O stream after the first character.
f.seek(5, IO::SEEK_CUR)
seek is a method of I/O stream which changes the position of the I/O stream by an offset of the first parameter from the second parameter. IO::SEEK_CUR is a constant which gives the current position of the I/O stream. So f.seek(5, IO::SEEK_CUR) moves the position to 5 places from the current position. (See IO#seek)
This will continue till a = f.getc becomes a false condition(here at the end of file, f.getc becomes nil, which is a falsey value in Ruby(false and nil are the only falsy values in Ruby, all others are truth values))
Use IRB to study and experiment with Ruby.
a = f.getc; puts a.chr outputs a single character; f.seek(5, IO::SEEK_CUR) moves forward by 5 characters.

Resources