Browse Source

First commit

master
alistair 4 years ago
commit
3f197848c4
  1. 22
      Makefile
  2. 6
      README.md
  3. 348
      cowsay.c

22
Makefile

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
.PHONY: default
default: main
debug: cowsay.c
gcc -g cowsay.c -o cowsay
install: main
cp cowsay /usr/local/bin/
main: cowsay.c
gcc -O3 cowsay.c -o cowsay
static: cowsay.c
gcc -O3 -static cowsay.c -o cowsay
clean: cowsay
rm cowsay

6
README.md

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
# c-cowsay
I was bored on an aeroplane so I decided to re-write Tony Monroe's cowsay in C.
It does not support multiple cow types or changing the features of the cow, but
after several more hours of lazy printf debugging it does wrap text in an almost-
identical way.

348
cowsay.c

@ -0,0 +1,348 @@ @@ -0,0 +1,348 @@
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
int read_file(FILE* in, char **out) {
int size_of_buffer = 20;
char *buffer = calloc(size_of_buffer, sizeof(char));
char character;
int count = 0;
while (true) {
character = fgetc(in);
if (character == EOF) {
buffer[count] = '\0';
*out = buffer;
return 0;
}
if (count == (size_of_buffer - 3)) {
buffer = reallocarray(buffer, (size_of_buffer *= 2), sizeof(char));
if (!buffer) {
return 1;
}
}
buffer[count] = character;
count++;
}
}
char *read_argvs(int argc, char**argv) {
int len = 1;
char *string = calloc(1, sizeof(char));
int clen = 0;
int now = 0;
for (int i = 1; i < argc; i++) {
int slen = strlen(argv[i]);
clen += slen;
if (clen == len) {
clen += 1;
}
if (clen >= len - 1) {
string = reallocarray(string, now + slen + 2, sizeof(char));
}
strcpy(&string[now], argv[i]);
strcpy(&(string[now + slen]), " ");
now = now + slen + 1;
}
return string;
}
// Remove duplicate instances of <del> so that a maximum of 3 consecutive
// remain
void strip_excess_char(char **text, char del) {
int len = strlen(*text);
int count = 0;
do {
char last_char = 'a';
char llast_char = 'a';
char this_char;
count = 0;
for (int i = 0; (*text)[i] != '\0'; i++) {
this_char = (*text)[i];
if (this_char == del && last_char == del && llast_char == del) {
count++;
if ((*text)[i+1] == '\0') {
/*(*text)[i-1] = '\0';*/
(*text)[i] = '\0';
break;
}
for (int j = i; (*text)[j] != '\0'; j++) {
/*(*text)[j-1] = (*text)[j];*/
/*(*text)[j] = (*text)[j+1];*/
(*text)[j] = (*text)[j+1];
}
//*text = reallocarray(*text, --len, sizeof(char));
}
llast_char = last_char;
last_char = this_char;
}
} while (count > 0);
}
void strip_tailing_whitespace(char *text) {
int len = strlen(text);
char *match = "\n\t ";
for (int i = len-1; i > 0; i ++) {
bool m = false;
for (int j = 0; j < strlen(match); j++) {
if (text[i] == match[j]) {
text[i] = '\0';
m = true;
break;
}
}
if (!m) {
break;
}
}
}
char *read_stdin(void) {
char *text;
int err = read_file(stdin, &text);
if (err) {
return NULL;
} else {
strip_excess_char(&text, '\n');
strip_excess_char(&text, '\t');
strip_excess_char(&text, ' ');
strip_tailing_whitespace(text);
return text;
}
}
char *get_text(int argc, char **argv) {
if (argc == 1) {
// stdin mode
return read_stdin();
} else if (argc > 1) {
// arg mode
return read_argvs(argc, argv);
}
return NULL;
}
void insert_char(char **str, char c, int p) {
int len = strlen(*str);
*str = reallocarray(*str, len + 3, sizeof(char));
for (int i = len-1; i >= p; i--) {
(*str)[i+1] = (*str)[i];
}
(*str)[p] = c;
}
// hard-warps string on spaces and long-lines to match width.
// @param width: the maximum width of the resulting string.
// @param text: The text to be wrapped. It is modified in place.
void wrap_text(char *text, int width) {
char *last_break = NULL;
int current_line = 0;
int last_break_pos = 0;
for (int i = 0; text[i] != '\0'; i++) {
if (text[i] == '\n') {
last_break = text + i;
last_break_pos = current_line;
current_line = 0;
}
char *breaks = "\t ";
// set whitespace to be break point
if ((text[i] == ' ') && current_line <= width + 2) {
last_break_pos = current_line;
last_break = text + i;
}
// force break on long liness
if ((current_line > width + 1) && last_break == NULL) {
insert_char(&text, '\n', i-1);
last_break = NULL;
current_line = 0;
} else if (current_line > width + 1) {
*last_break = '\n';
last_break = NULL;
current_line = current_line - last_break_pos;
}
current_line++;
}
}
void print_bubble(char *text, int width, int line_count) {
printf(" ");
for (int i = 0; i < width + 3; i ++) {
printf("_");
}
printf("\n");
int lc = 0;
int ll = 0;
for (int i = 0; text[i] != '\0'; i++) {
// printf("%d: %p = %c\n", i, text + i, text[i]);
if (ll == 0) {
if (lc == 0) {
printf("/ ");
} else if (lc == line_count) {
printf("\\ ");
} else {
printf("| ");
}
}
if (text[i] == '\n') {
for (;ll <= width; ll++) {
printf(" ");
}
if (lc == 0) {
printf(" \\\n");
} else if (lc == line_count) {
printf(" /\n");
} else {
printf(" |\n");
}
ll = -1;
lc++;
} else {
printf("%c", text[i]);
}
ll++;
}
for (;ll <= width; ll++) {
printf(" ");
}
if (lc == 0) {
printf(" \\\n");
} else if (lc == line_count ) {
printf(" /\n");
} else if (lc == line_count ) {
;
} else {
printf(" |\n");
}
printf(" ");
for (int i = 0; i < width + 3; i ++) {
printf("-");
}
}
void print_single_line_bubble(char *text, int len) {
printf(" ");
for (int i = 0; i < len + 1; i++) {
printf("_");
}
printf("\n<");
printf(" %s", text);
printf(">\n");
printf(" ");
for (int i = 0; i < len + 1; i++) {
printf("-");
}
printf("\n");
}
void print_speech(char *text, int width) {
int len = strlen(text);
if (len <= width) {
print_single_line_bubble(text, len);
return;
}
width -= 2; // for margins
wrap_text(text, width);
int line_count = 0;
for (int i = 0; text[i] != '\0'; i++) {
if (text[i] == '\n') {
line_count++;
}
}
print_bubble(text, width, line_count);
printf("\n");
}
struct Cow {
char *eyes;
char *tongue;
char *thoughts;
char *cow;
};
void print_cow(struct Cow *cow) {
char default_cow[] =
" \\ ^__^\n" \
" \\ (oo)\\_______\n" \
" (__)\\ )\\/\\\n" \
" ||----w |\n" \
" || ||\n" ;
char default_eyes[] = "oo";
char default_thoughts[] = "\\";
if (!cow->eyes) {
cow->eyes = default_eyes;
}
if (!cow->thoughts) {
cow->thoughts = default_thoughts;
}
if (!cow->cow) {
cow->cow = default_cow;
}
// TODO: write a replace string function to support cowfile-like
// substitution of features for $eyes, $tongue, and $thoughts into
// default_cow
printf("%s", default_cow);
}
int main(int argc, char** argv) {
char *text = get_text(argc, argv);
if (!text) {
return 1;
}
print_speech(text, 40);
struct Cow *cow = calloc(1, sizeof(struct Cow));
print_cow(cow);
}
Loading…
Cancel
Save