/* * cacamoo * Copyright (c) 2006 Jean-Yves Lamoureux * All Rights Reserved * * $Id$ * * This program is free software; you can redistribute it and/or * modify it under the terms of the Do What The Fuck You Want To * Public License, Version 2, as published by Sam Hocevar. See * http://sam.zoy.org/wtfpl/COPYING for more details. */ #include "config.h" #if defined(HAVE_INTTYPES_H) # include #endif #if defined(HAVE_GETOPT_H) # include #endif #if defined(HAVE_SYS_IOCTL_H) && defined(TIOCGWINSZ) # include #endif #include "cacamoo.h" #include char const *cacamoo_export = "utf8"; char const *cacamoo_file = "default"; char const *cacamoo_dir = "/usr/share/cowsay/cows"; /* Default glyphs */ char *cacamoo_eyes = "oo"; char *cacamoo_tongue = " "; char *cacamoo_thoughts = "\\"; char *cacamoo_think = "o"; char *cacamoo_borg = "=="; char *cacamoo_tired = "--"; char *cacamoo_dead = "xx"; char *cacamoo_greedy = "$$"; char *cacamoo_parano = "@@"; char *cacamoo_stoned = "**"; char *cacamoo_youth = ".."; char *cacamoo_wired = "OO"; char cacamoo_use_eyes[3] = {' ',' ',0}; char cacamoo_use_tongue[3] = {' ',' ',0}; /* String we have to display */ char *string = NULL; /* Wrapped and balloonified */ char *wrapped = NULL; /* Width */ unsigned int term_width = 40-1; /* Default for cowsay */ /* Think ? */ unsigned char think = 0; /* Unicode */ unsigned char unicode = 0; int main (int argc, char **argv) { int i, length; char *buffer = NULL; unsigned int buffer_size = 0; unsigned int new_width = 0; char *initial = NULL; unsigned int no_wrap = 0; cucul_buffer_t* input_buffer; cucul_buffer_t* output_buffer; cucul_canvas_t* canvas; int buf_size; char *buf_data; if ((strstr(argv[0], "cacathink")) != NULL) { think = 1; } #if defined(HAVE_GETOPT_H) for(;;) { # ifdef HAVE_GETOPT_LONG # define MOREINFO "Try `%s --help' for more information.\n" int option_index = 0; static struct option long_options[] = { /* Long option, needs arg, flag, short option */ { "file", 1, NULL, 'f' }, { "directory", 1, NULL, 'D' }, { "width", 1, NULL, 'W' }, { "no-wrap", 1, NULL, 'n' }, { "eyes", 1, NULL, 'e' }, { "tongue", 1, NULL, 'T' }, { "borg", 1, NULL, 'b' }, { "tired", 1, NULL, 't' }, { "dead", 1, NULL, 'd' }, { "greedy", 1, NULL, 'g' }, { "parano", 1, NULL, 'p' }, { "stoned", 1, NULL, 's' }, { "youth", 1, NULL, 'y' }, { "wired", 1, NULL, 'w' }, { "think", 1, NULL, 'O' }, { "unicode", 1, NULL, 'u' }, { "version", 0, NULL, 'v' }, { "list-files", 0, NULL, 'l' }, { "help", 0, NULL, 'h' }, { NULL, 0, NULL, 0 } }; int c = getopt_long(argc, argv, "D:f:W:e:T:hvObtdgpsylwnu", long_options, &option_index); # else # define MOREINFO "Try `%s -h' for more information.\n" int c = getopt(argc, argv, "D:f:W:hvObtdgpsylwnu"); # endif if(c == -1) break; switch(c) { case 'h': /* --help */ usage(); return 0; case 'v': /* --version */ version(); return 0; case 'f': /* --file*/ cacamoo_file = optarg; break; case 'D': /* --directory */ cacamoo_dir = optarg; break; case 'e': /* --eyes*/ cacamoo_eyes = optarg; break; case 'b': /* --borg*/ cacamoo_eyes = cacamoo_borg; break; case 't': /* --tired*/ cacamoo_eyes = cacamoo_tired; break; case 'd': /* --dead*/ cacamoo_eyes = cacamoo_dead; break; case 'g': /* --greedy*/ cacamoo_eyes = cacamoo_greedy; break; case 'p': /* --parano*/ cacamoo_eyes = cacamoo_parano; break; case 's': /* --stoned*/ cacamoo_eyes = cacamoo_stoned; break; case 'y': /* --youth*/ cacamoo_eyes = cacamoo_youth; break; case 'w': /* --wired*/ cacamoo_eyes = cacamoo_wired; break; case 'T': /* --tongue */ cacamoo_tongue = optarg; break; case 'O': /* --thoughts */ think = 1; break; case 'W': /* --width */ term_width = strtol(optarg, NULL, 10); if(term_width && (term_width != 1)) term_width--; break; case 'l': /* --list-files */ list_files("."); list_files(cacamoo_dir); return 0; break; case 'u': /* --unicode */ unicode = 1; break; case 'n': /* --no-wrap */ no_wrap = 1; break; case '?': printf(MOREINFO, argv[0]); return 1; default: printf("%s: invalid option -- %c\n", argv[0], c); printf(MOREINFO, argv[0]); return 1; } } #else # define MOREINFO "Usage: %s message...\n" int optind = 1; #endif if(think) cacamoo_thoughts = cacamoo_think; /* Load rest of commandline */ for(i = optind, length = 0; i < argc; i++) { unsigned int k, guessed_len, real_len = 0; guessed_len = strlen(argv[i]); if(i > optind) string[length++] = ' '; string = realloc(string, (length + guessed_len + 1)); for(k = 0, real_len = 0; k < guessed_len; real_len++) { string[length + real_len] = *(argv[i]+k); k ++; } length += real_len; } if(string == NULL) { usage(); return -1; } string[length] = 0; /* Eyes and tongue are 2 characters wide */ memcpy(cacamoo_use_eyes, cacamoo_eyes, strlen(cacamoo_eyes)>2?2:strlen(cacamoo_eyes)); memcpy(cacamoo_use_tongue, cacamoo_tongue, strlen(cacamoo_tongue)>2?2:strlen(cacamoo_tongue)); initial = malloc(strlen(string)+1); memcpy(initial, string, strlen(string)+1); free(string); wrapped = wrap_string(initial, term_width, &new_width, no_wrap); string = wrapped; buffer = make_caca_from_file(&buffer_size); if(buffer == NULL) { if(string) free(string); return -1; } /* Import our buffer as an ansi (color) one */ input_buffer = cucul_load_memory(buffer, buffer_size-1); if(input_buffer == NULL) { printf("Can't load file in libcucul !\n"); return -1; } canvas = cucul_import_canvas (input_buffer, unicode?"utf8":"ansi"); if(canvas == NULL) { printf("Can't load file in libcucul !\n"); return -1; } /* Export given canvas to format we want */ output_buffer = cucul_export_canvas(canvas, "ansi"); if(output_buffer == NULL) { printf("Can't export file to text !\n"); return -1; } buf_size = cucul_get_buffer_size(output_buffer); buf_data = cucul_get_buffer_data(output_buffer); for(i = 0; i < buf_size; i++) printf("%c", buf_data[i]); if(string) free(string); if(buffer) free(buffer); cucul_free_buffer(input_buffer); cucul_free_buffer(output_buffer); cucul_free_canvas(canvas); return 0; } void list_files(const char *directory) { struct dirent * dp; int count = 0; DIR *dir = opendir(directory); for (dp = readdir(dir); dp != NULL; dp = readdir(dir)) { if(!strncmp(&dp->d_name[strlen(dp->d_name)-4], ".cow", 4)) { char name[256]; memcpy(name, dp->d_name, strlen(dp->d_name)-4); name[strlen(dp->d_name)-4] = 0; printf("%s ", name); count++; if(!(count%6)) printf("\n"); } } closedir(dir); if(count) printf("\n"); return; } char * make_caca_from_file(unsigned int *size) { FILE *fp = NULL; char filepath[1024]; unsigned int s = 0; char *temp = NULL; /* Try direct name */ snprintf(filepath, 1023, "%s", cacamoo_file); fp = fopen(filepath, "r"); if(fp == NULL) { /* Try direct file + .cow */ snprintf(filepath, 1023, "%s.cow", cacamoo_file); fp = fopen(filepath, "r"); if(fp == NULL) { /* Try with complete directory */ snprintf(filepath, 1023, "%s/%s.cow", cacamoo_dir, cacamoo_file); fp = fopen(filepath, "r"); if(fp == NULL) { printf("Can't open %s\n", filepath); perror("fopen"); return NULL; } } } fseek(fp, 0, SEEK_END); s = ftell(fp); fseek(fp, 0, SEEK_SET); temp = malloc(s+1*sizeof(char)); if(temp == NULL) { printf("Not enough memory.\n"); return NULL; } if(fread(temp, 1, s, fp)!=s) { printf("Can't read %s\n", filepath); perror("fread"); return NULL; } temp[s] = '\0'; temp = remove_comments(temp); temp = remove_slashes(temp); /* AHAHAH, THAT'S A COOL PERL INTERPRETER ! */ temp = replace(temp, " = <<\"EOC\";", ""); temp = replace(temp, " = < Version: 0, date: 30 Sep 2006\n"); printf("\n"); } #if defined(HAVE_GETOPT_H) static void usage(void) { printf("Usage: cacamoo [ -vh ] [ -d cowsdirectory ]\n"); printf(" [ -f cowfile ] [ -w outputwidth ]\n"); printf(" [-bdgpstwy] [ message ]\n"); # ifdef HAVE_GETOPT_LONG printf(" -f, --file select the cow\n"); printf(" -d, --directory specify cows directory\n"); printf(" -W, --width set output width\n"); printf(" -n --no-wrap do not wrap string\n"); printf(" -O, --think think\n"); printf(" -h display this help and exit\n"); printf(" -v, --version output version information and exit\n"); # else printf(" -f select the cow\n"); printf(" -d specify cows directory\n"); printf(" -W set output width\n"); printf(" -n --no-wrap do not wrap string\n"); printf(" -O, --think think\n"); printf(" -h display this help and exit\n"); printf(" -v output version information and exit\n"); # endif } #endif /* AHAHAHAHA please make no comment about this, I was in hurry \o/ */ char *wrap_string(char *buffer, unsigned int width, unsigned int *max_width, int no_wrap) { unsigned int i = 0, j =0, o = 0, last_space = 0, line = 0, offset = 0; unsigned int size = strlen(buffer) + 1, t = 0, rew = 0; char *ret = NULL; ret = malloc(2); *max_width = 0; /* Wrap string itself */ if(size > width && !no_wrap) { while(i= *max_width) *max_width = width - (i - last_space); i = last_space + 1; last_space = 0; rew = 0; } else { if(width>= *max_width) *max_width = width; } offset = 0; line ++; } ret = realloc(ret, o+2); ret[o++] = buffer[i]; i++; offset++; } if(offset>= *max_width) *max_width = offset; if(!(*max_width)) *max_width = size-1; ret[o] = 0; line++; } else { *max_width = strlen(buffer); if(ret) free(ret); ret = buffer; line = 1; } /* String is wrapped, put spaces after each line */ if(line != 1) { char *scaled = malloc(((*max_width+1) * line) + 1); int curx = 0; memset(scaled, ' ', (*max_width * line)); o = 0; for(i = 0; i < strlen(ret); i ++) { if(ret[i] != '\n') { scaled[o] = ret[i]; curx++; } else { for(j=o;j