Skip to content

Instantly share code, notes, and snippets.

@ericek111
Last active February 16, 2026 08:51
Show Gist options
  • Select an option

  • Save ericek111/f029e77aa5ac6cb98795af78220ec750 to your computer and use it in GitHub Desktop.

Select an option

Save ericek111/f029e77aa5ac6cb98795af78220ec750 to your computer and use it in GitHub Desktop.
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#define MAX_NUM_BUFFER_LEN 64
struct num_reader
{
// file descriptors for reading/writing, can be stdin, stdout
FILE* in;
FILE* out;
// the currently processed character
char charin;
// this is the buffer that will hold our number, it will be converted later
char* numBuffer;
char* numCursor;
char* numEnd;
// status flags
bool shouldDoConversion;
bool ignoreNext;
};
typedef struct num_reader num_reader;
num_reader* num_reader_create(FILE* in, FILE* out) {
num_reader* ret = malloc(sizeof(num_reader));
if (ret == NULL) {
return NULL;
}
ret->numBuffer = malloc(MAX_NUM_BUFFER_LEN * sizeof(char));
ret->numCursor = ret->numBuffer;
ret->numEnd = ret->numBuffer + MAX_NUM_BUFFER_LEN;
if (ret->numBuffer == NULL) {
return NULL;
}
ret->in = in;
ret->out = out;
ret->shouldDoConversion = false;
ret->ignoreNext = false;
return ret;
}
void num_reader_reset_numbuffer(num_reader* reader, bool flushToOut) {
if (flushToOut) {
fputs(reader->numBuffer, reader->out);
}
reader->numCursor = reader->numBuffer;
memset(reader->numBuffer, 0, MAX_NUM_BUFFER_LEN * sizeof(char));
reader->shouldDoConversion = false;
}
void num_reader_abandon_conversion(num_reader* reader) {
num_reader_reset_numbuffer(reader, true);
// and don't forget to print the F that we consumend.
fputc('F', reader->out);
}
void num_reader_convert_number(num_reader* reader) {
errno = 0;
double tempF = strtod(reader->numBuffer, NULL);
if (errno) {
// number is invalid/too high, don't do any conversions
// we should probably set some sort of error flag
num_reader_abandon_conversion(reader);
true;
}
double tempC = (tempF - 32.0) * (5.0 / 9.0);
fprintf(reader->out, "%.2fC", tempC);
num_reader_reset_numbuffer(reader, false);
}
bool num_reader_is_a_number_char(char in) {
const char* wordBoundary = ".,+-()|{}/* \n\t\r";
return strchr(wordBoundary, in) == NULL;
}
void num_reader_process_char(num_reader* reader) {
char charin = reader->charin;
if (reader->shouldDoConversion) {
if (num_reader_is_a_number_char(charin)) {
// user is high, something like "42.0F69" was passed.
num_reader_abandon_conversion(reader);
// and also prevent next numbers from being printed.
reader->ignoreNext = true;
} else {
num_reader_convert_number(reader);
fputc(charin, reader->out);
return;
}
}
if (reader->ignoreNext) {
if (!num_reader_is_a_number_char(charin)) {
reader->ignoreNext = false;
}
fputc(charin, reader->out);
return;
}
if (!(isdigit(charin) || charin == '.' || charin == '-')) {
// if the character is NOT a number (or a dot, or a minus sign)
if (reader->numCursor == reader->numBuffer) {
// We're not appending to the num buffer, it's some garbage,
// perhaps just a normal letter. Print it unchanged.
fputc(charin, reader->out);
} else if (charin == 'F') {
// We do have something in the num buffer and now we see an F.
// DO THE CONVERSION when the next char comes
reader->shouldDoConversion = true;
return;
} else {
// We have something in the buffer and a character other
// than F follows, so it's not a temperature. Flush the buffer.
num_reader_reset_numbuffer(reader, true);
// and don't forget about this character.
fputc(charin, reader->out);
}
return;
}
bool willIgnoreNext = false;
if (reader->numCursor == reader->numBuffer && charin == '.') {
// We don't support this notation (".2F"), let's not care about it.
willIgnoreNext = true;
} else if (charin == '-') {
// we're past the first character and we've received a minus sign?!
// that's not a valid number, maybe some separator (----)?
willIgnoreNext = true;
}
*reader->numCursor++ = charin;
if (reader->numCursor == reader->numEnd) {
// this is some crazily long number... discard it.
willIgnoreNext = true;
}
if (willIgnoreNext) {
num_reader_reset_numbuffer(reader, true);
reader->ignoreNext = true;
}
}
int num_reader_run(num_reader* reader) {
char charin;
while ((charin = fgetc(reader->in)) != EOF) {
reader->charin = charin;
num_reader_process_char(reader);
}
if (reader->shouldDoConversion) {
// we still have a conversion pending? okay, let's do it then.
num_reader_convert_number(reader);
}
return 0;
}
void num_reader_free(num_reader* reader) {
free(reader->numBuffer);
free(reader);
}
int main(int argc, char const *argv[]) {
num_reader* reader = num_reader_create(stdin, stdout);
if (!reader) {
printf("Error");
return 1;
}
int ret = num_reader_run(reader);
num_reader_free(reader);
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment