|  | // Copyright 2016 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include <stdio.h> | 
|  | #include <string.h> | 
|  |  | 
|  | #define MAX_WIDTH 40 | 
|  | #define MAX(a, b) ((a > b) ? a : b) | 
|  | #define MIN(a, b) ((a < b) ? a : b) | 
|  |  | 
|  | // Returns the length of the longst line of the message. | 
|  | static size_t LongestLineLength(int argc, char** argv) { | 
|  | size_t max_len = 0; | 
|  | size_t cur_line = 0; | 
|  |  | 
|  | for (int i = 0; i < argc; i++) { | 
|  | size_t word_len = strlen(argv[i]) + 1; | 
|  |  | 
|  | // If the word itself is too long to fit in a line, then | 
|  | // we return the maximum width. | 
|  | if (word_len >= MAX_WIDTH) | 
|  | return MAX_WIDTH; | 
|  |  | 
|  | if (cur_line + word_len >= MAX_WIDTH) { | 
|  | cur_line = word_len; | 
|  | } else { | 
|  | cur_line += word_len; | 
|  | } | 
|  |  | 
|  | max_len = MAX(cur_line, max_len); | 
|  | } | 
|  |  | 
|  | return max_len; | 
|  | } | 
|  |  | 
|  | static void PrintPaddedBreak(size_t pad) { | 
|  | for (size_t i = 0; i < pad; i++) { | 
|  | printf(" "); | 
|  | } | 
|  | printf(" |\n"); | 
|  | } | 
|  |  | 
|  | // Prints the message | 
|  | static void PrintMessage(int argc, char** argv, size_t longest) { | 
|  | size_t cur_line_len = 0; | 
|  |  | 
|  | for (int i = 0; i < argc; i++) { | 
|  | size_t word_len = strlen(argv[i]) + 1; | 
|  |  | 
|  | if (cur_line_len == 0) | 
|  | printf("| "); | 
|  |  | 
|  | // If it all fits in the line, then print the word and move on. | 
|  | if (cur_line_len + word_len <= MAX_WIDTH) { | 
|  | printf("%s ", argv[i]); | 
|  |  | 
|  | if (cur_line_len + word_len == MAX_WIDTH) { | 
|  | PrintPaddedBreak(longest - cur_line_len - word_len); | 
|  | cur_line_len = 0; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | cur_line_len += word_len; | 
|  |  | 
|  | if (i == argc - 1) | 
|  | PrintPaddedBreak(longest - cur_line_len); | 
|  |  | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // Create a line break if the current line is nonempty. | 
|  | if (cur_line_len > 0) { | 
|  | PrintPaddedBreak(longest - cur_line_len); | 
|  | printf("| "); | 
|  | } | 
|  |  | 
|  | // If the word itself is too long, then we need to break it apart. | 
|  | // Otherwise, we print the current word and move on. | 
|  | if (word_len > MAX_WIDTH) { | 
|  | char* str = argv[i]; | 
|  | size_t processed = 0; | 
|  | for (size_t j = 0; j <= word_len / MAX_WIDTH; j++) { | 
|  | size_t len = MIN(MAX_WIDTH, strlen(str)); | 
|  | printf("%.*s", (int)len, str); | 
|  | PrintPaddedBreak(longest - len); | 
|  | str += len; | 
|  | processed += len; | 
|  | if (processed >= word_len - 1) | 
|  | break; | 
|  | printf("| "); | 
|  | } | 
|  |  | 
|  | cur_line_len = 0; | 
|  | } else { | 
|  | printf("%s ", argv[i]); | 
|  | cur_line_len = word_len; | 
|  | if (word_len == MAX_WIDTH || i == argc - 1) { | 
|  | PrintPaddedBreak(longest - cur_line_len); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | int main(int argc, char** argv) { | 
|  | if (argc == 1) { | 
|  | printf("Usage: cowsay [message]\n"); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | // No wordwrap because I'm too lazy. | 
|  | size_t bubble_width = LongestLineLength(argc - 1, argv + 1) + 1; | 
|  |  | 
|  | printf(" _"); | 
|  | for (size_t i = 0; i < bubble_width; i++) | 
|  | printf("_"); | 
|  | printf(" \n"); | 
|  |  | 
|  | PrintMessage(argc - 1, argv + 1, bubble_width - 1); | 
|  |  | 
|  | printf(" -"); | 
|  | for (size_t i = 0; i < bubble_width; i++) | 
|  | printf("-"); | 
|  | printf(" \n"); | 
|  |  | 
|  | printf("     \\  ^__^\n"); | 
|  | printf("      \\ (oo)\\_____\n"); | 
|  | printf("        (__)\\     )\\/\\\n"); | 
|  | printf("           ||----w |\n"); | 
|  | printf("           ||     ||\n"); | 
|  |  | 
|  | return 0; | 
|  | } |