|
|
@@ -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; |
|
|
|
} |
|
|
|
|