#include #include #include static const char *SLOPES = "\\_/"; static char *error_message = NULL; typedef struct { int width, height; char data[]; } Panorama; int check_source(char *source) { ssize_t total_length, slope_length; total_length = strlen(source); slope_length = strspn(source, SLOPES); return (total_length == slope_length) ? total_length : -1; } int slope_to_delta(char slope) { return strchr(SLOPES, slope) - SLOPES - 1; } uint* calculate_heights(uint width, char *source, int *max_height) { uint i; int current_height, delta; uint *heights; heights = malloc(width * sizeof(heights)); *max_height = 0; for (current_height = i = 0; i < width; ++i) { heights[i] = current_height; delta = slope_to_delta(source[i]); current_height += delta; if (current_height < 0) { free(heights); error_message = "panorama drops below baseline"; return NULL; } if (delta == -1) heights[i] = current_height; if (current_height > *max_height) *max_height = current_height; } ++*max_height; return heights; } Panorama* Panorama_new(int width, int height, char *source, uint *heights) { Panorama *result; int data_size; int i; data_size = width * height; result = malloc(sizeof(*result) + data_size); result->width = width; result->height = height; memset(result->data, ' ', data_size); for (i = 0; i < width; ++i) { result->data[width * (height - heights[i] - 1) + i] = source[i]; } return result; } Panorama* Panorama_from_string(char *source) { int width, height; uint *heights; Panorama *result = NULL; width = check_source(source); if (width == -1) { error_message = "illegal characters in argument"; return NULL; } heights = calculate_heights(width, source, &height); if (heights) { result = Panorama_new(width, height, source, heights); free(heights); } return result; } void Panorama_print(Panorama *panorama) { int i, j; char *ptr; ptr = panorama->data; for (i = 0; i < panorama->height; ++i) { for (j = 0; j < panorama->width; ++j) { putchar(*ptr++); } putchar('\n'); } } void Panorama_free(Panorama *panorama) { if (panorama) { panorama->width = panorama->height = 0; free(panorama); } } int main(int argc, char **argv) { Panorama *panorama; if (argc < 2) { printf("usage: %s panoramastring\n", argv[0]); return 1; } panorama = Panorama_from_string(argv[1]); if (panorama) { Panorama_print(panorama); Panorama_free(panorama); } else { puts(error_message); return 2; } return 0; }