aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--src/fractal_render.c130
-rw-r--r--src/fractal_render.h5
-rw-r--r--src/fractals.c14
-rw-r--r--src/grids.c19
-rw-r--r--src/grids.h2
6 files changed, 153 insertions, 20 deletions
diff --git a/.gitignore b/.gitignore
index 0ce3b70..ec428fc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
+# grid files
+*.grid
+
# Presentation Stuff
build/*
*.html
diff --git a/src/fractal_render.c b/src/fractal_render.c
index bac8202..b9ffa09 100644
--- a/src/fractal_render.c
+++ b/src/fractal_render.c
@@ -1,18 +1,134 @@
#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <setjmp.h>
+
#include "grids.h"
#include "precision.h"
#include "fractal_render.h"
+void print_usage(FILE* file, const char* program_name) {
+ fprintf(file, "Usage: %s -i input.grid [-r renderer] [-o output.ext]\n", program_name);
+}
+
+void print_help(){
+ printf("Options:\n"
+ " -i, --input <input grid> the grid to be rendered, if the file name is '-' reads from stdin\n"
+ " -r, --renderer <renderer> the renderer to use, defaults to the text renderer\n"
+ " renderers: txt, png (TODO), gif (TODO, with additional features)\n"
+ " -o, --output <output file> the file to output the result of rendering, if not given defaults to output.<EXT>\n"
+ " where <EXT> is the renderer used\n"
+ " -v, --verbose verbose output\n"
+ " -h, --help prints this help and exits\n"
+ );
+}
+
+jmp_buf error_buffer;
+
+/*
+ * Error logger that causes used file streams to be closed
+ */
+void error_exit(const char* message, const char* issue) {
+ if(issue){
+ fprintf(stderr, "%s: %s\n", message, issue);
+ }
+ else {
+ fprintf(stderr, "%s\n", message);
+ }
+ longjmp(error_buffer, 1);
+}
+
+/*
+ * Cleanup io files and a grid
+ */
+void cleanup(FILE* output_file, FILE* input_file, grid_t* grid) {
+ if(output_file) fclose(output_file);
+ // closing stdin is not recommended, can supposedly cause odd behvaior
+ if(input_file && input_file != stdin) fclose(input_file);
+ if(grid) free_grid(grid);
+}
+
+
int main(const int argc, char* argv[]){
- char* input_file = "test.grid";
- FILE* file = fopen(input_file, "rb");
- grid_t* grid = read_grid(file);
- fclose(file);
+ char* input_filename = "fractal.grid";
+ char* output_filename = "fractal.txt";
+ renderer_func renderer = print_grid;
+ bool verbose = false;
+
+ static struct option long_options[] = {
+ {"input", required_argument, NULL, 'i'},
+ {"renderer", required_argument, NULL, 'r'},
+ {"output", required_argument, NULL, 'o'},
+ {"verbose", no_argument, NULL, 'v'},
+ {"help", no_argument, NULL, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ int opt;
+ while((opt = getopt_long(argc, argv, "i:r:o:vh", long_options, NULL)) != -1){
+ switch(opt){
+ case 'i':
+ input_filename = optarg;
+ break;
+ case 'r':
+ //TODO: update with other renderers
+ renderer = print_grid;
+ break;
+ case 'o':
+ output_filename = optarg;
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 'h':
+ print_usage(stdout, argv[0]);
+ print_help();
+ return 0;
+ default:
+ print_usage(stderr, argv[0]);
+ fprintf(stderr, "See --help for more info\n");
+ return 1;
+
+ }
+ }
+ //TODO: logic to set output_filename if o flag is not used
+
+ FILE* input_file = NULL;
+ FILE* output_file = NULL;
+ grid_t* grid = NULL;
+
+ if (setjmp(error_buffer) != 0) {
+ cleanup(output_file, input_file, grid);
+ exit(EXIT_FAILURE);
+ }
+
+ if(strcmp(output_filename, "-") == 0){
+ output_file = stdout;
+ }
+ else {
+ output_file = fopen(output_filename, "wb");
+ if (!output_file) { error_exit("Error opening output file", output_filename); }
+ }
+
+ if(strcmp(input_filename, "-") == 0){
+ grid = read_grid(stdin);
+ if (!grid) { error_exit("Error reading from stdin", NULL); }
+ }
+ else {
+ input_file = fopen(input_filename, "rb");
+ if (!input_file) { error_exit("Error opening input file", input_filename); }
+ grid = read_grid(input_file);
+ if (!grid) { error_exit("Error reading from file", input_filename); }
+ }
+
+ if(verbose){
+ print_grid_info(grid);
+ }
- if(!grid) return 1;
+ renderer(output_file, grid);
- print_grid_info(grid);
+ cleanup(output_file, input_file, grid);
- free_grid(grid);
return 0;
}
diff --git a/src/fractal_render.h b/src/fractal_render.h
index 6f70f09..a23acad 100644
--- a/src/fractal_render.h
+++ b/src/fractal_render.h
@@ -1 +1,6 @@
#pragma once
+
+#include <stdio.h>
+#include "grids.h"
+
+typedef void (*renderer_func)(FILE*, const grid_t*);
diff --git a/src/fractals.c b/src/fractals.c
index 4d8967e..395ccdb 100644
--- a/src/fractals.c
+++ b/src/fractals.c
@@ -193,17 +193,21 @@ int main(const int argc, char *argv[]) {
}
//use "safer" versions of c string functions
- if(strncmp(output_filename, "-", 1) && strnlen(output_filename, 16) == 1){
+ //likely aren't necessary unless a user can pass non-null terminated strings as arguments, but that would likely break something up in getopt
+ if(output_filename[0] == '-' && strnlen(output_filename, 16) == 1){
if(write_grid(stdout, grid) == GRID_WRITE_ERROR){
- fprintf(stderr, "Error writing occured while writting to file %s\n", output_filename);
+ fprintf(stderr, "Error occured while writting to file %s\n", output_filename);
}
}
else {
FILE* file = fopen(output_filename, "wb");
- if(write_grid(file, grid) == GRID_WRITE_ERROR){
- fprintf(stderr, "Error writing occured while writting to file %s\n", output_filename);
+ if(!file){
+ perror("Error occured while trying to write");
}
- fclose(file);
+ else if(write_grid(file, grid) == GRID_WRITE_ERROR){
+ fprintf(stderr, "Error occured while writting to file %s\n", output_filename);
+ }
+ fclose(file);
}
free(params);
diff --git a/src/grids.c b/src/grids.c
index 2bb87e6..354189b 100644
--- a/src/grids.c
+++ b/src/grids.c
@@ -233,7 +233,7 @@ void print_grid_info(const grid_t* grid){
/*
* Attempts an ASCII print of the grid
*/
-void print_grid(const grid_t* grid){
+void print_grid(FILE* file, const grid_t* grid){
const size_t size = grid->size;
const size_t x_res = grid->x;
const size_t iterations = grid->max_iterations;
@@ -241,15 +241,18 @@ void print_grid(const grid_t* grid){
//TODO: set values in output buffer rather than multiple printf calls
// the buffer needs to be larger to hold newlines
- // char* output_buffer = malloc(size);
- // if(!output_buffer){
- // fprintf(stderr, "Failed to allocate output buffer for %zu points\n");
- // return;
- // }
+ char* output_buffer = malloc(size + grid->y-1);
+ if(!output_buffer){
+ fprintf(stderr, "Failed to allocate output buffer for %zu points\n", size);
+ return;
+ }
+
+ setvbuf(file, output_buffer, _IOFBF, size + grid->y - 1);
const char point_types[] = { ' ', '.', '*', '%', '#'};
size_t bin_width = iterations/3;
size_t last_bin = iterations - bin_width;
+ char* buffer_ptr = output_buffer;
char point;
for(size_t i = 0; i < size; i++){
@@ -269,8 +272,10 @@ void print_grid(const grid_t* grid){
else {
point = point_types[2];
}
- printf("%c%s", point, (i % x_res == x_res - 1) ? "\n" : "");
+ fprintf(file ,"%c%s", point, (i % x_res == x_res - 1) ? "\n" : "");
}
+ fflush(file);
+ free(output_buffer);
}
/*
diff --git a/src/grids.h b/src/grids.h
index b823c91..293ceb5 100644
--- a/src/grids.h
+++ b/src/grids.h
@@ -44,6 +44,6 @@ CBASE complex grid_to_complex(const grid_t* grid, const size_t index);
void zoom_grid(grid_t* grid, const CBASE magnification);
void print_grid_info(const grid_t* grid);
-void print_grid(const grid_t* grid);
+void print_grid(FILE* file, const grid_t* grid);
int write_grid(FILE* file, const grid_t* grid);
grid_t* read_grid(FILE* file);