shithub: orca

Download patch

ref: ae16f05272b88cbf0ec7aea3d6ef8562eb6d010d
parent: 94b57818a450b6799ee2848098539738214bc3bb
author: cancel <cancel@cancel.fm>
date: Sun Nov 25 05:07:18 EST 2018

Add basic loading of grid fields from file

--- a/base.h
+++ b/base.h
@@ -6,6 +6,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 typedef char Term;
 typedef uint32_t U32;
--- a/cli_main.c
+++ b/cli_main.c
@@ -1,15 +1,63 @@
 #include "base.h"
 #include "field.h"
-#include <unistd.h>
+#include <getopt.h>
 
 int main(int argc, char** argv) {
-  (void)argc;
-  (void)argv;
+  static struct option cli_options[] = {{"time", required_argument, 0, 't'},
+                                        {NULL, 0, NULL, 0}};
+
+  char* input_file = NULL;
+  int ticks = 0;
+
+  for (;;) {
+    int c = getopt_long(argc, argv, "t:", cli_options, NULL);
+    if (c == -1)
+      break;
+    switch (c) {
+    case 't':
+      ticks = atoi(optarg);
+      break;
+    }
+  }
+
+  if (optind == argc - 1) {
+    input_file = argv[optind];
+  }
+
+  if (input_file == NULL) {
+    fprintf(stderr, "No input file\n");
+    return 1;
+  }
+  if (ticks < 0) {
+    fprintf(stderr, "Time must be >= 0\n");
+    return 1;
+  }
+
   Field field;
-  field_init_fill(&field, 32, 32, '.');
-  field_fill_subrect(&field, 1, 1, field.height - 2, field.width - 2, 'a');
-  field_fill_subrect(&field, 2, 2, field.height - 4, field.width - 4, 'b');
-  field_fill_subrect(&field, 3, 3, field.height - 6, field.width - 6, '.');
+  field_init(&field);
+  Field_load_error fle = field_load_file(input_file, &field);
+  if (fle != Field_load_error_ok) {
+    field_deinit(&field);
+    char const* errstr = "Unknown";
+    switch (fle) {
+      case Field_load_error_ok:
+        break;
+      case Field_load_error_cant_open_file:
+        errstr = "Unable to open file";
+        break;
+      case Field_load_error_too_many_columns:
+        errstr = "Grid file has too many columns";
+        break;
+      case Field_load_error_no_rows_read:
+        errstr = "Grid file has no rows";
+        break;
+      case Field_load_error_not_a_rectangle:
+        errstr = "Grid file is not a rectangle";
+        break;
+    }
+    fprintf(stderr, "File load error: %s\n", errstr);
+    return 1;
+  }
   field_fput(&field, stdout);
   field_deinit(&field);
   return 0;
--- a/field.c
+++ b/field.c
@@ -1,10 +1,10 @@
 #include "field.h"
+#include <ctype.h>
 
-void field_init_zeros(Field* f, U32 height, U32 width) {
-  size_t num_cells = height * width;
-  f->buffer = calloc(num_cells, sizeof(Term));
-  f->height = height;
-  f->width = width;
+void field_init(Field* f) {
+  f->buffer = NULL;
+  f->height = 0;
+  f->width = 0;
 }
 
 void field_init_fill(Field* f, U32 height, U32 width, Term fill_char) {
@@ -22,13 +22,7 @@
   f->width = width;
 }
 
-void field_deinit(Field* f) {
-  assert(f->buffer != NULL);
-  free(f->buffer);
-#ifndef NDEBUG
-  f->buffer = NULL;
-#endif
-}
+void field_deinit(Field* f) { free(f->buffer); }
 
 void field_copy_subrect(Field* src, Field* dest, U32 src_y, U32 src_x,
                         U32 dest_y, U32 dest_x, U32 height, U32 width) {
@@ -112,7 +106,8 @@
   size_t f_height = f->height;
   size_t f_width = f->width;
   assert(y < f_height && x < f_width);
-  if (y >= f_height || x >= f_width) return '\0';
+  if (y >= f_height || x >= f_width)
+    return '\0';
   return f->buffer[y * f_width + x];
 }
 
@@ -120,10 +115,15 @@
   size_t f_height = f->height;
   size_t f_width = f->width;
   assert(y < f_height && x < f_width);
-  if (y >= f_height || x >= f_width) return;
+  if (y >= f_height || x >= f_width)
+    return;
   f->buffer[y * f_width + x] = term;
 }
 
+inline bool term_char_is_valid(char c) {
+  return c >= '#' && c <= '~';
+}
+
 void field_fput(Field* f, FILE* stream) {
   enum { Column_buffer_count = 4096 };
   char out_buffer[Column_buffer_count];
@@ -136,14 +136,56 @@
     Term* row_p = f_buffer + f_width * iy;
     for (size_t ix = 0; ix < f_width; ++ix) {
       char c = row_p[ix];
-      if (c >= '#' && c <= '~') {
-        out_buffer[ix] = c;
-      } else {
-        out_buffer[ix] = '!';
-      }
+      out_buffer[ix] = term_char_is_valid(c) ? c : '!';
     }
     out_buffer[f_width] = '\n';
     out_buffer[f_width + 1] = '\0';
     fputs(out_buffer, stream);
   }
+}
+
+Field_load_error field_load_file(char const* filepath, Field* field) {
+  FILE* file = fopen(filepath, "r");
+  if (file == NULL) {
+    return Field_load_error_cant_open_file;
+  }
+  enum { Bufsize = 4096 };
+  char buf[Bufsize];
+  U32 first_row_columns = 0;
+  U32 rows = 0;
+  for (;;) {
+    char* s = fgets(buf, Bufsize, file);
+    if (s == NULL)
+      break;
+    size_t len = strlen(buf);
+    if (len == Bufsize - 1 && buf[len - 1] != '\n' && !feof(file)) {
+      fclose(file);
+      return Field_load_error_too_many_columns;
+    }
+    for (;;) {
+      if (len == 0)
+        break;
+      if (!isspace(buf[len - 1]))
+        break;
+      --len;
+    }
+    if (len == 0)
+      continue;
+    // quick hack until we use a proper scanner
+    if (rows == 0) {
+      first_row_columns = len;
+    } else if (len != first_row_columns) {
+      fclose(file);
+      return Field_load_error_not_a_rectangle;
+    }
+    field_resize_raw(field, rows + 1, first_row_columns);
+    Term* rowbuff = field->buffer + first_row_columns * rows;
+    for (size_t i = 0; i < len; ++i) {
+      char c = buf[i];
+      rowbuff[i] = term_char_is_valid(c) ? c : '!';
+    }
+    ++rows;
+  }
+  fclose(file);
+  return Field_load_error_ok;
 }
--- a/field.h
+++ b/field.h
@@ -1,7 +1,7 @@
 #pragma once
 #include "base.h"
 
-void field_init_zeros(Field* f, U32 height, U32 width);
+void field_init(Field* f);
 void field_init_fill(Field* f, U32 height, U32 width, Term fill_char);
 void field_resize_raw(Field* f, U32 height, U32 width);
 void field_deinit(Field* f);
@@ -13,3 +13,13 @@
 void field_poke(Field* f, U32 y, U32 x, Term term);
 
 void field_fput(Field* f, FILE* stream);
+
+typedef enum {
+  Field_load_error_ok = 0,
+  Field_load_error_cant_open_file = 1,
+  Field_load_error_too_many_columns = 2,
+  Field_load_error_no_rows_read = 3,
+  Field_load_error_not_a_rectangle = 4,
+} Field_load_error;
+
+Field_load_error field_load_file(char const* filepath, Field* field);