#include <stdio.h> #include <stdlib.h> #include <stdint.h> // fixed sized integer #include <stdbool.h> // booleans typedef struct Tile { uint32_t x; uint32_t y; } Tile; typedef enum ReadResult { RdOk, RdEof, RdErrIntegerOverflow, RdErrNonDigitCharacter, RdErrTooFewNumbers, RdErrTooManyNumbers, } ReadResult; typedef struct Field { Tile t_min; Tile t_max; uint32_t num_tiles; } Field; /** Parsen einer Kachel(Tile) aus einer Zeile von StdIn * * Die Zahlen werden in das uebergebene Struct pKachel geschrieben, sind aber * nur gueltig, wenn der Rueckgabewert `Ok` ist. */ ReadResult read_line(Tile* p_tile){ int c = getchar(); if (c == EOF) { return RdEof; } int num_numbers = 0; bool cur_whitespace = true; while(1) { c = getchar(); if ('0' <= c && c <= '9') { if (cur_whitespace) { num_numbers++; cur_whitespace = false; } uint32_t *p_cur; switch(num_numbers) { case 1: p_cur = &p_tile->x; break; case 2: p_cur = &p_tile->y; break; default: return RdErrTooManyNumbers; } // 429496730 = 2^32 / 10, daher wenn `p_cur` groesser ist, wird ein // overflow erzeugt if (*p_cur > 429496729) { printf("Multiplizieren ueberlauf %u\n", *p_cur); return RdErrIntegerOverflow; } (*p_cur) *= 10; int digit = c - '0'; if (*p_cur > UINT32_MAX - digit) { printf("Addieren ueberlauf %u\n", *p_cur); return RdErrIntegerOverflow; } (*p_cur) += digit; } else if (c == ' ') { if (cur_whitespace == true) { cur_whitespace = false; } } else if (c == '\n') { if (num_numbers == 2) { return RdOk; } else { return RdErrTooFewNumbers; } } else { return RdErrNonDigitCharacter; } } return RdOk; } /** * */ inline uint32_t min(uint32_t a, uint32_t b) { return a < b ? a : b; } inline uint32_t max(uint32_t a, uint32_t b) { return a > b ? a : b; } /** Liest das Input von StdIn und schreibt das Ergebnis in das uebergebene Feld * * Parameter: * - Field* f pointer auf ein uninitialisiertes Feld, nach dem ausfuehren der * Funktion ist das Feld initialisiert, wenn es sich um eine gueltige Eingabe * handelt. `f->num_tiles` Ist im Fehlerfall die Zeile, in dem die Eingabe * ungueltig ist. * * Return: * - ReadResult: * RdOk, falls das lesen erfolgreich war * RdErr..., falls die eingabe ungueltig ist. f ist dann nicht vollstaendig * initialisiert */ ReadResult parse_input(Field *f) { f->t_min.x = UINT32_MAX; f->t_min.y = UINT32_MAX; f->t_max.x = 0; f->t_max.y = 0; f->num_tiles = 0; while (1) { Tile t; ReadResult result = read_line(&t); f->num_tiles++; switch (result) { case RdOk: // Reichweite des Feldes ermitteln f->t_min.x = min(f->t_min.x, t.x); f->t_min.y = min(f->t_min.y, t.y); f->t_max.x = max(f->t_max.x, t.x); f->t_max.y = max(f->t_max.x, t.y); break; case RdEof: if (f->num_tiles == 1) { return RdEof; } else { return RdOk; } default: // error return result; } } } int main (int argc, char *argv[]) { Field f; ReadResult result = parse_input(&f); switch (result) { case RdOk: printf("Valider Input"); printf("Anzahl: %d", f.num_tiles); printf("Range(%d, %d), (%d, %d)", f.t_min.x, f.t_min.y, f.t_max.x, f.t_max.y); printf("Range x: %d, %d", f.t_max.x - f.t_min.x, f.t_max.y - f.t_min.y); break; case RdEof: // bei leerer Eingabe nichts ausgeben return EXIT_SUCCESS; case RdErrIntegerOverflow: fprintf(stderr, "Error in line %d: too big integer\n", f.num_tiles); return EXIT_FAILURE; case RdErrNonDigitCharacter: fprintf(stderr, "Error in line %d: invalid character\n", f.num_tiles); return EXIT_FAILURE; case RdErrTooFewNumbers: fprintf(stderr, "Error in line %d: Too few numbers, expected exactly 2\n", f.num_tiles); return EXIT_FAILURE; case RdErrTooManyNumbers: fprintf(stderr, "Error in line %d: Too much numbers, expected exactly 2\n", f.num_tiles); return EXIT_FAILURE; } return EXIT_SUCCESS; }