Przeglądaj źródła

* Initial revision

git-svn-id: file:///srv/caca.zoy.org/var/lib/svn/cacamoo/trunk@1244 92316355-f0b4-4df1-b90c-862c8a59935f
master
jylam 18 lat temu
rodzic
commit
baa95798cc
7 zmienionych plików z 799 dodań i 15 usunięć
  1. +3
    -0
      TODO
  2. +9
    -0
      configure.ac
  3. +1
    -1
      data/Makefile.am
  4. +13
    -0
      data/caca.cow
  5. +1
    -1
      src/Makefile.am
  6. +35
    -0
      src/cacamoo.h
  7. +737
    -13
      src/main.c

+ 3
- 0
TODO Wyświetl plik

@@ -0,0 +1,3 @@
Handle COWPATH env var
Support color (through ANSI)
Support unicode

+ 9
- 0
configure.ac Wyświetl plik

@@ -25,6 +25,15 @@ if test "$build" != "$host" -a "${PKG_CONFIG_LIBDIR}" = ""; then
export PKG_CONFIG_LIBDIR=/dev/null
fi

AC_CHECK_HEADERS(getopt.h)

AC_CHECK_FUNCS(getopt_long,
[AC_DEFINE(HAVE_GETOPT_LONG, 1, Define to 1 if you have the `getopt_long' function.)],
[AC_CHECK_LIB(gnugetopt, getopt_long,
[AC_DEFINE(HAVE_GETOPT_LONG, 1, Define to 1 if you have the `getopt_long' function.)
GETOPT_LIBS="${GETOPT_LIBS} -lgnugetopt"])])
AC_SUBST(GETOPT_LIBS)

CACA="no"
PKG_CHECK_MODULES(cucul, cucul,
[CACA="yes"],


+ 1
- 1
data/Makefile.am Wyświetl plik

@@ -1 +1 @@
EXTRA_DIST =
EXTRA_DIST = caca.cow

+ 13
- 0
data/caca.cow Wyświetl plik

@@ -0,0 +1,13 @@
# A nice caca cow !
# (c) 2006 Jean-Yves Lamoureux
# So much work must be copyrighted, as MOZILLA(tm)(c)(r) team told me.

$the_cow
$thoughts
$thoughts
$thoughts
/
( )
( $eyes )
(______)
$tongue

+ 1
- 1
src/Makefile.am Wyświetl plik

@@ -1,7 +1,7 @@

bin_PROGRAMS = cacamoo

cacamoo_SOURCES = main.c
cacamoo_SOURCES = main.c cacamoo.h
cacamoo_CFLAGS = `pkg-config --cflags cucul`
cacamoo_LDFLAGS = `pkg-config --libs cucul`


+ 35
- 0
src/cacamoo.h Wyświetl plik

@@ -0,0 +1,35 @@
/*
* cacamoo
* Copyright (c) 2006 Jean-Yves Lamoureux <jylam@lnxscene.org>
* 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.
*/

#ifndef _CACASAY_H_
#define _CACASAY_H_

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <cucul.h>


static void version(void);
char *construct_balloon(char *buffer, unsigned int termwidth);
char *wrap_string(char *buffer, unsigned int width, unsigned int *max_width, int no_wrap);
char *make_caca_from_file(unsigned int *size);
char *replace(char *string, char *oldpiece, const char *newpiece);
char *remove_slashes(char *str);
char *remove_comments(char *str);

#if defined(HAVE_GETOPT_H)
static void usage(void);
#endif

#endif /* _CACASAY_H_ */

+ 737
- 13
src/main.c Wyświetl plik

@@ -1,27 +1,751 @@
/*
* $Id$
* cacamoo
* Copyright (c) 2006 Jean-Yves Lamoureux <jylam@lnxscene.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* $Id$
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* 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 <inttypes.h>
#endif
#if defined(HAVE_GETOPT_H)
# include <getopt.h>
#endif
#if defined(HAVE_SYS_IOCTL_H) && defined(TIOCGWINSZ)
# include <sys/ioctl.h>
#endif

#include "cacamoo.h"
#include <cucul.h>

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;


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' },
{ "version", 0, NULL, 'v' },
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 }
};



int c = getopt_long(argc, argv, "D:f:W:e:T:hvObtdgpsywn",
long_options, &option_index);
# else
# define MOREINFO "Try `%s -h' for more information.\n"
int c = getopt(argc, argv, "D:f:W:hvObtdgpsywn");
# 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 'n': /* --width */
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);
canvas = cucul_import_canvas (input_buffer, "ansi");
/* Export given canvas to format we want */
output_buffer = cucul_export_canvas(canvas, "irc");

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);

return 0;
}


char * make_caca_from_file(unsigned int *size)
{
FILE *fp = NULL;
char filepath[1024];
unsigned int s = 0;
char *temp = NULL;
char *temp2 = 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 = remove_comments(temp);
temp = remove_slashes(temp);


/* AHAHAH, THAT'S A COOL PERL INTERPRETER ! */
temp2 = replace(temp, " = <<\"EOC\";", "");
if(temp2 != temp)
{
free(temp);
temp = temp2;
}
temp2 = replace(temp, " = <<EOC;" , "");
if(temp2 != temp)
{
free(temp);
temp = temp2;
}
temp2 = replace(temp, " = <<EOC" , "");
if(temp2 != temp)
{
free(temp);
temp = temp2;
}
temp2 = replace(temp, " = << EOC" , "");
if(temp2 != temp)
{
free(temp);
temp = temp2;
}
temp2 = replace(temp, "EOC" , "");
if(temp2 != temp)
{
free(temp);
temp = temp2;
}
temp2 = replace(temp, "$eyes" , cacamoo_use_eyes);
if(temp2 != temp)
{
free(temp);
temp = temp2;
}
temp2 = replace(temp, "${eyes}" , cacamoo_use_eyes);
if(temp2 != temp)
{
free(temp);
temp = temp2;
}

temp2 = replace(temp, "$tongue" , cacamoo_use_tongue);
if(temp2 != temp)
{
free(temp);
temp = temp2;
}
temp2 = replace(temp, "${tongue}" , cacamoo_use_tongue);
if(temp2 != temp)
{
free(temp);
temp = temp2;
}

temp2 = replace(temp, "$thoughts" , cacamoo_thoughts);
if(temp2 != temp)
{
free(temp);
temp = temp2;
}
temp2 = replace(temp, "${thoughts}" , cacamoo_thoughts);
if(temp2 != temp)
{
free(temp);
temp = temp2;
}

temp2 = replace(temp, "$the_cow" , (const char*)string);
if(temp2 != temp)
{
free(temp);
temp = temp2;
}
temp2 = replace(temp, "${the_cow}" , (const char*)string);
if(temp2 != temp)
{
free(temp);
temp = temp2;
}

*size = strlen(temp)+1;


fclose(fp);
return temp;
}
char *remove_slashes(char *str)
{
int i=0, size, r=0;

if(str == NULL) return NULL;

size = strlen(str);

for(i=0; i<size-r; i++)
{
if(str[i]== '\\')
{
memmove(&str[i], &str[i+1], strlen(str) - i);
str = realloc(str, (size-r)+1);
r++;
}
}
return str;
}


char *remove_comments(char *str)
{
int size = 0, added=0;
int i=0, j;

if(str == NULL) return NULL;

size = strlen(str) + 1;

while(i < size)
{
if(str[i] == '#') {
for(j = i; j < size; j++)

if((str[j] == '\n') || (str[j] == '\r') || (str[j] == 0))
goto hop; // just because I like goto's, break sucks
hop:
j++;
added += (i-j);
memmove(&str[i], &str[j], size-j);
i = j - added;
size -= added;
str = realloc(str, size);
str[size-1] = 0;
i = 0;
}
else
i++;
}
return str;
}


char *replace(char *str, char *oldpiece, const char *newpiece)
{
int str_index, newstr_index, oldpiece_index, end,
new_len, old_len, cpy_len;
char *c = NULL;
char *newstr = NULL;

if(oldpiece==NULL || newpiece==NULL)
return NULL;

if ((c = (char *) strstr(str, oldpiece)) == NULL) {
return str;
}

newstr = malloc(1024);

if(newstr == NULL)
{
return str;
}

new_len = strlen(newpiece);
old_len = strlen(oldpiece);
end = strlen(str) - old_len;
oldpiece_index = c - str;

newstr_index = 0;
str_index = 0;
while(str_index <= end && c != NULL)
{
/* Copy characters from the left of matched pattern occurence */
cpy_len = oldpiece_index-str_index;
strncpy(newstr+newstr_index, str+str_index, cpy_len);
newstr_index += cpy_len;
str_index += cpy_len;

/* Copy replacement characters instead of matched pattern */
strcpy(newstr+newstr_index, newpiece);
newstr_index += new_len;
str_index += old_len;

/* Check for another pattern match */
if((c = (char *) strstr(str+str_index, oldpiece)) != NULL)
oldpiece_index = c - str;


}
/* Copy remaining characters from the right of last matched pattern */
strcpy(newstr+newstr_index, str+str_index);

return newstr;
}


static void version(void)
{
printf("cacamoo Copyright 2006 Jean-Yves Lamoureux %s\n", VERSION);
printf("Internet: <jylam@lnscene.org> 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 <cowfile> select the cow\n");
printf(" -d, --directory <dir> specify cows directory\n");
printf(" -W, --width <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 <cowfile> select the cow\n");
printf(" -d <dir> 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 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<size-1)
{
if(buffer[i] == ' ')
{
last_space = i;
rew = o;
}
if(offset == width)
{
ret = realloc(ret, o+2);
if(rew)
o = rew;
ret[o++] = '\n';

if(last_space) {

if(width - (i - last_space) >= *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<o+(*max_width - curx);j++)
{
scaled[j] = ' ';

}
o += ((*max_width) - curx) -1;
curx = 0;
}
o++;
}
for(i = o; i <o+(*max_width - curx); i ++)
{
scaled[i] = ' ';
}

scaled[o+i] = 0;
if(ret)
free(ret);
ret = scaled;


/* Put balloon */
o = 0;
scaled = malloc((*max_width+5) * (line+2));

scaled[t++] = ' ';
for(i = 0; i < *max_width+2; i++)
scaled[t++] = '_';
scaled[t++] = ' ';
scaled[t++] = '\n';


for(j = 0; j < line ; j++)
{
if(think)
{
scaled[t++] = '(';
}
else
{
if(j == 0)
scaled[t++] = '/';
else if (j == line -1)
scaled[t++] = '\\';
else
scaled[t++] = '|';
}
scaled[t++] = ' ';

for(i = 0; i < *max_width; i++)
{
scaled[t++] = ret[o++];
}
scaled[t++] = ' ';
if(think)
{
scaled[t++] = ')';
}
else
{
if(j == 0)
scaled[t++] = '\\';
else if (j == line -1)
scaled[t++] = '/';
else
scaled[t++] = '|';
}
scaled[t++] = '\n';
}

scaled[t++] = ' ';
for(i = 0; i < *max_width+2; i++)
scaled[t++] = '-';
scaled[t++] = ' ';
scaled[t] = 0;

free(ret);
ret = NULL;
ret = scaled;
}
else
{
/* Put ballon */
char *scaled = malloc((size+4) * 3);
t = 0;
*max_width = size -1 ;
o = 0;
scaled[t++] = ' ';
for(i = 0; i < *max_width+2; i++)
scaled[t++] = '_';
scaled[t++] = ' ';
scaled[t++] = '\n';
if(think)
scaled[t++] = '(';
else
scaled[t++] = '<';
scaled[t++] = ' ';
for(i = 0; i < *max_width; i++)
{
scaled[t++] = ret[o++];
}
scaled[t++] = ' ';
if(think)
scaled[t++] = ')';
else
scaled[t++] = '>';

scaled[t++] = '\n';
scaled[t++] = ' ';
for(i = 0; i < *max_width+2; i++)
scaled[t++] = '-';

free(ret);
ret = NULL;
ret = scaled;
}


return ret;
}


Ładowanie…
Anuluj
Zapisz