Does zig
have functions that are equivalent to C library’s getchar()
and ungetc(ch1, stdin)
?
readByte
is the getchar()
equivalent. You can get a std.io.Reader
using the reader()
method of the file or network stream.
There is no ungetc
in the standard library. You can use a char: ?u8
(optional byte) to implement ungetc
like:
var char: ?u8 = null;
fn ungetc(ch: u8) void {
char = ch;
}
fn getchar(reader: Reader) !u8 {
if (char) |ch| {
char = null;
return ch;
}
return reader.readByte();
}
Welcome to ziggit
char = ch
?..
Yes, thank you.
Hey, that’s actually a pretty cool solution. The global variable makes me slightly worried, but I’ve got some ideas how to work around it.
The only really limitation is that it would only allow a single character ungetc
(but that would not be something that I would need right now at least).
This “buffer” can be placed into some struct with getc
/ungetc
methods or so.
BTW, here is a snippet from man ungetc
:
ungetc() pushes c back to stream, cast to unsigned char, where it is
available for subsequent read operations. Pushed-back characters will
be returned in reverse order; only one pushback is guaranteed.
So “one-byte push-back buffer” is quite a “legal” solution.
That’s interesting. I never tried to ungetc
more than one character, but I somehow assumed that it would work just fine if I did push back more. It’s always a good idea to read the spec/man, etc.
const std = @import("std");
const CharReader = struct {
char: ?u8,
reader: std.io.Reader,
fn init(reader: std.io.Reader) CharReader {
return .{
.char = null,
.reader = reader,
};
}
fn ungetc(self: CharReader, ch: u8) void {
self.char = ch;
}
fn getchar(self: CharReader) !u8 {
if (self.char) |ch| {
self.char = null;
return ch;
}
return self.reader.readByte();
}
};
This is exactly what I was looking for! Thanks!
(I’m very new to zig and there are many “d’oh” moments when I crack my brain to figure out the correct way… and then I see the solution and it elegant and simple)
It won’t, but you can use a stack (can be implemented using generic ArrayList
from standard library, for ex.). If pop
operation returns null
, do actual reading.
Off-topic. I personally never used ungetc()
. How can it be useful at all? Multiple input handlers?.. I searched a bit and found this.
I can’t find any useful examples of how this function could be necessary
Just out of curiosity, what are you using ungetc()
for?
Maybe it is not the most elegant solution, but I sometimes use it for key detection.
- ESC =
27
- UP_ARROW =
27[A
- A = A
So, if I want to detect both ESC, UP_ARROW and A, etc, I must “ignore” the first ESC and read the next character. If the next character is not [
, then I can ungetc
and continue
the loop to capture it as another key that was pressed after normal ESC.