Last active
February 16, 2026 08:51
-
-
Save ericek111/f029e77aa5ac6cb98795af78220ec750 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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