source: cacamoo/trunk/src/main.c @ 1244

Last change on this file since 1244 was 1244, checked in by Jean-Yves Lamoureux, 14 years ago
  • Initial revision
  • Property svn:keywords set to Id
File size: 18.1 KB
Line 
1/*
2 *  cacamoo
3 *  Copyright (c) 2006 Jean-Yves Lamoureux <jylam@lnxscene.org>
4 *                All Rights Reserved
5 *
6 *  $Id: main.c 1244 2006-10-26 20:59:01Z jylam $
7 *
8 *  This program is free software; you can redistribute it and/or
9 *  modify it under the terms of the Do What The Fuck You Want To
10 *  Public License, Version 2, as published by Sam Hocevar. See
11 *  http://sam.zoy.org/wtfpl/COPYING for more details.
12 */
13
14
15#include "config.h"
16
17#if defined(HAVE_INTTYPES_H)
18#   include <inttypes.h>
19#endif
20#if defined(HAVE_GETOPT_H)
21#   include <getopt.h>
22#endif
23#if defined(HAVE_SYS_IOCTL_H) && defined(TIOCGWINSZ)
24#   include <sys/ioctl.h>
25#endif
26
27#include "cacamoo.h"
28#include <cucul.h>
29
30char const *cacamoo_export = "utf8";
31char const *cacamoo_file = "default";
32char const *cacamoo_dir = "/usr/share/cowsay/cows";
33
34/* Default glyphs */
35char *cacamoo_eyes = "oo";
36char *cacamoo_tongue = "  ";
37char *cacamoo_thoughts = "\\";
38char *cacamoo_think = "o";
39char *cacamoo_borg = "==";
40char *cacamoo_tired = "--";
41char *cacamoo_dead = "xx";
42char *cacamoo_greedy = "$$";
43char *cacamoo_parano = "@@";
44char *cacamoo_stoned = "**";
45char *cacamoo_youth = "..";
46char *cacamoo_wired = "OO";
47char cacamoo_use_eyes[3] = {' ',' ',0};
48char cacamoo_use_tongue[3] = {' ',' ',0};
49
50/* String we have to display */
51char *string = NULL;
52/* Wrapped and balloonified */
53char *wrapped = NULL;
54
55
56/* Width */
57unsigned int term_width = 40-1; /* Default for cowsay */
58
59/* Think ? */
60unsigned char think = 0;
61
62
63int main (int argc, char **argv)
64{
65    int i, length;
66    char *buffer = NULL;
67    unsigned int buffer_size = 0;
68    unsigned int new_width = 0;
69    char *initial = NULL;
70    unsigned int no_wrap = 0;
71    cucul_buffer_t* input_buffer;
72    cucul_buffer_t* output_buffer;
73    cucul_canvas_t* canvas;
74    int buf_size;
75    char *buf_data;
76
77    if ((strstr(argv[0], "cacathink")) != NULL) {
78        think = 1;
79    }
80
81#if defined(HAVE_GETOPT_H)
82    for(;;)
83    {
84#   ifdef HAVE_GETOPT_LONG
85#       define MOREINFO "Try `%s --help' for more information.\n"
86        int option_index = 0;
87        static struct option long_options[] =
88            {
89                /* Long option, needs arg, flag, short option */
90                { "file", 1, NULL, 'f' },
91                { "directory", 1, NULL, 'D' },
92                { "width", 1, NULL, 'W' },
93                { "no-wrap", 1, NULL, 'n' },
94                { "eyes", 1, NULL, 'e' },
95                { "tongue", 1, NULL, 'T' },
96                { "borg", 1, NULL, 'b' },
97                { "tired", 1, NULL, 't' },
98                { "dead", 1, NULL, 'd' },
99                { "greedy", 1, NULL, 'g' },
100                { "parano", 1, NULL, 'p' },
101                { "stoned", 1, NULL, 's' },
102                { "youth", 1, NULL, 'y' },
103                { "wired", 1, NULL, 'w' },
104                { "think", 1, NULL, 'O' },
105                { "version", 0, NULL, 'v' },
106                { "help", 0, NULL, 'h' },
107                { NULL, 0, NULL, 0 }
108            };
109
110
111
112        int c = getopt_long(argc, argv, "D:f:W:e:T:hvObtdgpsywn",
113                            long_options, &option_index);
114#   else
115#       define MOREINFO "Try `%s -h' for more information.\n"
116        int c = getopt(argc, argv, "D:f:W:hvObtdgpsywn");
117#   endif
118        if(c == -1)
119            break;
120
121        switch(c)
122        {
123        case 'h': /* --help */
124            usage();
125            return 0;
126        case 'v': /* --version */
127            version();
128            return 0;
129        case 'f': /* --file*/
130            cacamoo_file = optarg;
131            break;
132        case 'D': /* --directory */
133            cacamoo_dir = optarg;
134            break;
135        case 'e': /* --eyes*/
136            cacamoo_eyes = optarg;
137            break;
138        case 'b': /* --borg*/
139            cacamoo_eyes = cacamoo_borg;
140            break;
141        case 't': /* --tired*/
142            cacamoo_eyes = cacamoo_tired;
143            break;
144        case 'd': /* --dead*/
145            cacamoo_eyes = cacamoo_dead;
146            break;
147        case 'g': /* --greedy*/
148            cacamoo_eyes = cacamoo_greedy;
149            break;
150        case 'p': /* --parano*/
151            cacamoo_eyes = cacamoo_parano;
152            break;
153        case 's': /* --stoned*/
154            cacamoo_eyes = cacamoo_stoned;
155            break;
156        case 'y': /* --youth*/
157            cacamoo_eyes = cacamoo_youth;
158            break;
159        case 'w': /* --wired*/
160            cacamoo_eyes = cacamoo_wired;
161            break;
162        case 'T': /* --tongue */
163            cacamoo_tongue = optarg;
164            break;
165        case 'O': /* --thoughts */
166            think = 1;
167            break;
168        case 'W': /* --width */
169            term_width = strtol(optarg, NULL, 10);
170            if(term_width && (term_width != 1)) term_width--;
171            break;
172        case 'n': /* --width */
173            no_wrap = 1;
174            break;
175        case '?':
176            printf(MOREINFO, argv[0]);
177            return 1;
178        default:
179            printf("%s: invalid option -- %c\n", argv[0], c);
180            printf(MOREINFO, argv[0]);
181            return 1;
182        }
183    }
184#else
185#   define MOREINFO "Usage: %s message...\n"
186    int optind = 1;
187#endif
188
189    if(think)
190        cacamoo_thoughts = cacamoo_think;
191
192    /* Load rest of commandline */
193    for(i = optind, length = 0; i < argc; i++)
194    {
195        unsigned int k, guessed_len, real_len = 0;
196
197        guessed_len = strlen(argv[i]);
198
199        if(i > optind)
200            string[length++] = ' ';
201
202        string = realloc(string, (length + guessed_len + 1));
203
204        for(k = 0, real_len = 0; k < guessed_len; real_len++)
205        {
206            string[length + real_len] = *(argv[i]+k);
207            k ++;
208        }
209        length += real_len;
210    }
211
212    if(string == NULL) {
213        usage();
214        return -1;
215    }
216
217    string[length] = 0;
218
219
220    /* Eyes and tongue are 2 characters wide */
221    memcpy(cacamoo_use_eyes, cacamoo_eyes, strlen(cacamoo_eyes)>2?2:strlen(cacamoo_eyes));
222    memcpy(cacamoo_use_tongue, cacamoo_tongue, strlen(cacamoo_tongue)>2?2:strlen(cacamoo_tongue));
223
224    initial = malloc(strlen(string)+1);
225    memcpy(initial, string, strlen(string)+1);
226    free(string);
227
228    wrapped = wrap_string(initial, term_width, &new_width, no_wrap);
229    string = wrapped;
230
231    buffer = make_caca_from_file(&buffer_size);
232    if(buffer == NULL)
233    {
234        if(string)
235            free(string);
236        return -1;
237    }
238
239
240    /* Import our buffer as an ansi (color) one */
241    input_buffer = cucul_load_memory(buffer, buffer_size);
242    canvas = cucul_import_canvas (input_buffer, "ansi");
243    /* Export given canvas to format we want */
244    output_buffer = cucul_export_canvas(canvas, "irc");
245
246    buf_size = cucul_get_buffer_size(output_buffer);
247    buf_data = cucul_get_buffer_data(output_buffer);
248
249    for(i = 0; i < buf_size; i++)
250        printf("%c", buf_data[i]);
251
252    if(string)
253        free(string);
254    if(buffer)
255        free(buffer);
256
257    return 0;
258}
259
260
261char * make_caca_from_file(unsigned int *size)
262{
263    FILE *fp = NULL;
264    char filepath[1024];
265    unsigned int s = 0;
266    char *temp = NULL;
267    char *temp2 = NULL;
268
269    /* Try direct name */
270    snprintf(filepath, 1023, "%s", cacamoo_file);
271    fp = fopen(filepath, "r");
272    if(fp == NULL)
273    {
274        /* Try direct file + .cow */
275        snprintf(filepath, 1023, "%s.cow", cacamoo_file);
276        fp = fopen(filepath, "r");
277        if(fp == NULL)
278        {
279            /* Try with complete directory */
280            snprintf(filepath, 1023, "%s/%s.cow", cacamoo_dir, cacamoo_file);
281            fp = fopen(filepath, "r");
282            if(fp == NULL)
283            {
284                printf("Can't open %s\n", filepath);
285                perror("fopen");
286                return NULL;
287            }
288        }
289    }
290
291
292    fseek(fp, 0, SEEK_END);
293    s = ftell(fp);
294    fseek(fp, 0, SEEK_SET);
295
296
297    temp = malloc(s+1*sizeof(char));
298    if(temp == NULL) {
299        printf("Not enough memory.\n");
300        return NULL;
301    }
302
303    if(fread(temp, 1, s, fp)!=s)
304    {
305        printf("Can't read %s\n", filepath);
306        perror("fread");
307        return NULL;
308    }
309
310
311    temp = remove_comments(temp);
312    temp = remove_slashes(temp);
313
314
315    /* AHAHAH, THAT'S A COOL PERL INTERPRETER ! */
316    temp2 = replace(temp, " = <<\"EOC\";", "");
317    if(temp2 != temp)
318    {
319        free(temp);
320        temp = temp2;
321    }
322    temp2 = replace(temp, " = <<EOC;"    , "");
323    if(temp2 != temp)
324    {
325        free(temp);
326        temp = temp2;
327    }
328    temp2 = replace(temp, " = <<EOC"     , "");
329    if(temp2 != temp)
330    {
331        free(temp);
332        temp = temp2;
333    }
334    temp2 = replace(temp, " = << EOC"    , "");
335    if(temp2 != temp)
336    {
337        free(temp);
338        temp = temp2;
339    }
340    temp2 = replace(temp, "EOC"          , "");
341    if(temp2 != temp)
342    {
343        free(temp);
344        temp = temp2;
345    }
346    temp2 = replace(temp, "$eyes"        , cacamoo_use_eyes);
347    if(temp2 != temp)
348    {
349        free(temp);
350        temp = temp2;
351    }
352    temp2 = replace(temp, "${eyes}"      , cacamoo_use_eyes);
353    if(temp2 != temp)
354    {
355        free(temp);
356        temp = temp2;
357    }
358
359    temp2 = replace(temp, "$tongue"      , cacamoo_use_tongue);
360    if(temp2 != temp)
361    {
362        free(temp);
363        temp = temp2;
364    }
365    temp2 = replace(temp, "${tongue}"    , cacamoo_use_tongue);
366    if(temp2 != temp)
367    {
368        free(temp);
369        temp = temp2;
370    }
371
372    temp2 = replace(temp, "$thoughts"    , cacamoo_thoughts);
373    if(temp2 != temp)
374    {
375        free(temp);
376        temp = temp2;
377    }
378    temp2 = replace(temp, "${thoughts}"  , cacamoo_thoughts);
379    if(temp2 != temp)
380    {
381        free(temp);
382        temp = temp2;
383    }
384
385    temp2 = replace(temp, "$the_cow"     , (const char*)string);
386    if(temp2 != temp)
387    {
388        free(temp);
389        temp = temp2;
390    }
391    temp2 = replace(temp, "${the_cow}"   , (const char*)string);
392    if(temp2 != temp)
393    {
394        free(temp);
395        temp = temp2;
396    }
397
398    *size = strlen(temp)+1;
399
400
401    fclose(fp);
402    return temp;
403}
404char *remove_slashes(char *str)
405{
406    int i=0, size, r=0;
407
408    if(str == NULL) return NULL;
409
410    size = strlen(str);
411
412    for(i=0; i<size-r; i++)
413    {
414        if(str[i]== '\\')
415        {
416            memmove(&str[i], &str[i+1], strlen(str) - i);
417            str = realloc(str, (size-r)+1);
418            r++;
419        }
420    }
421    return str;
422}
423
424
425char *remove_comments(char *str)
426{
427    int size = 0, added=0;
428    int i=0, j;
429
430    if(str == NULL) return NULL;
431
432    size = strlen(str) + 1;
433
434    while(i < size)
435    {
436        if(str[i] == '#') {
437            for(j = i; j < size; j++)
438
439                if((str[j] == '\n') || (str[j] == '\r') || (str[j] == 0))
440                    goto hop; // just because I like goto's, break sucks
441        hop:
442            j++;
443            added += (i-j);
444            memmove(&str[i], &str[j], size-j);
445            i = j - added;
446            size -= added;
447            str = realloc(str, size);
448            str[size-1] = 0;
449            i = 0;
450        }
451        else
452            i++;
453    }
454    return str;
455}
456
457
458char *replace(char *str, char *oldpiece, const char *newpiece)
459{
460    int str_index, newstr_index, oldpiece_index, end,
461        new_len, old_len, cpy_len;
462    char *c = NULL;
463    char *newstr = NULL;
464
465    if(oldpiece==NULL || newpiece==NULL)
466        return NULL;
467
468    if ((c = (char *) strstr(str, oldpiece)) == NULL) {
469        return str;
470    }
471
472    newstr = malloc(1024);
473
474    if(newstr == NULL)
475    {
476        return str;
477    }
478
479    new_len        = strlen(newpiece);
480    old_len        = strlen(oldpiece);
481    end            = strlen(str)   - old_len;
482    oldpiece_index = c - str;
483
484    newstr_index = 0;
485    str_index = 0;
486    while(str_index <= end && c != NULL)
487    {
488        /* Copy characters from the left of matched pattern occurence */
489        cpy_len = oldpiece_index-str_index;
490        strncpy(newstr+newstr_index, str+str_index, cpy_len);
491        newstr_index += cpy_len;
492        str_index    += cpy_len;
493
494        /* Copy replacement characters instead of matched pattern */
495        strcpy(newstr+newstr_index, newpiece);
496        newstr_index += new_len;
497        str_index    += old_len;
498
499        /* Check for another pattern match */
500        if((c = (char *) strstr(str+str_index, oldpiece)) != NULL)
501            oldpiece_index = c - str;
502
503
504    }
505    /* Copy remaining characters from the right of last matched pattern */
506    strcpy(newstr+newstr_index, str+str_index);
507
508    return newstr;
509}
510
511
512static void version(void)
513{
514    printf("cacamoo Copyright 2006 Jean-Yves Lamoureux %s\n", VERSION);
515    printf("Internet: <jylam@lnscene.org> Version: 0, date: 30 Sep 2006\n");
516    printf("\n");
517}
518
519#if defined(HAVE_GETOPT_H)
520static void usage(void)
521{
522    printf("Usage: cacamoo [ -vh ] [ -d cowsdirectory ]\n");
523    printf("               [ -f cowfile ] [ -w outputwidth ]\n");
524    printf("               [-bdgpstwy]    [ message ]\n");
525#   ifdef HAVE_GETOPT_LONG
526    printf("  -f, --file <cowfile>     select the cow\n");
527    printf("  -d, --directory <dir>    specify cows directory\n");
528    printf("  -W, --width <width>      set output width\n");
529    printf("  -n  --no-wrap            do not wrap string\n");
530    printf("  -O, --think              think\n");
531    printf("  -h                       display this help and exit\n");
532    printf("  -v, --version            output version information and exit\n");
533#   else
534    printf("  -f <cowfile>     select the cow\n");
535    printf("  -d <dir>         specify cows directory\n");
536    printf("  -W <width>       set output width\n");
537    printf("  -n  --no-wrap            do not wrap string\n");
538    printf("  -O, --think      think\n");
539    printf("  -h               display this help and exit\n");
540    printf("  -v               output version information and exit\n");
541#   endif
542}
543#endif
544
545
546/* AHAHAHAHA please make no comment about this, I was in hurry \o/ */
547
548char *wrap_string(char *buffer, unsigned int width, unsigned int *max_width, int no_wrap)
549{
550    unsigned int i = 0, j =0, o = 0, last_space = 0, line = 0, offset  = 0;
551    unsigned int size = strlen(buffer) + 1, t = 0, rew = 0;
552    char *ret = NULL;
553    ret = malloc(2);
554    *max_width = 0;
555
556    /* Wrap string itself */
557    if(size > width && !no_wrap)
558    {
559        while(i<size-1)
560        {
561            if(buffer[i] == ' ')
562            {
563                last_space = i;
564                rew = o;
565            }
566            if(offset == width)
567            {
568                ret = realloc(ret, o+2);
569                if(rew)
570                    o = rew;
571                ret[o++] = '\n';
572
573                if(last_space) {
574
575                    if(width - (i - last_space) >= *max_width)
576                        *max_width = width - (i - last_space);
577
578                    i = last_space + 1;
579                    last_space = 0;
580                    rew = 0;
581
582                } else {
583                    if(width>= *max_width)
584                        *max_width = width;
585                }
586
587
588                offset = 0;
589                line ++;
590            }
591            ret = realloc(ret, o+2);
592            ret[o++] = buffer[i];
593
594            i++;
595            offset++;
596        }
597        if(offset>= *max_width)
598            *max_width = offset;
599        if(!(*max_width))
600            *max_width = size-1;
601
602        ret[o] = 0;
603        line++;
604    }
605    else
606    {
607        *max_width = strlen(buffer);
608        if(ret)
609            free(ret);
610        ret = buffer;
611        line = 1;
612    }
613
614    /* String is wrapped, put spaces after each line */
615    if(line != 1)
616    {
617        char *scaled = malloc(((*max_width+1) * line) + 1);
618        int curx = 0;
619
620        memset(scaled, ' ', (*max_width * line));
621        o = 0;
622        for(i = 0; i < strlen(ret); i ++)
623        {
624            if(ret[i] != '\n')
625            {
626                scaled[o] = ret[i];
627                curx++;
628            }
629            else
630            {
631                for(j=o;j<o+(*max_width - curx);j++)
632                {
633                    scaled[j] = ' ';
634
635                }
636                o += ((*max_width) - curx) -1;
637                curx = 0;
638            }
639            o++;
640        }
641        for(i = o; i <o+(*max_width - curx); i ++)
642        {
643            scaled[i] = ' ';
644        }
645
646        scaled[o+i] = 0;
647        if(ret)
648            free(ret);
649        ret = scaled;
650
651
652        /* Put balloon */
653        o = 0;
654        scaled = malloc((*max_width+5) * (line+2));
655
656        scaled[t++] = ' ';
657        for(i = 0; i < *max_width+2; i++)
658            scaled[t++] = '_';
659        scaled[t++] = ' ';
660        scaled[t++] = '\n';
661
662
663        for(j = 0; j < line ; j++)
664        {
665            if(think)
666            {
667                scaled[t++] = '(';
668            }
669            else
670            {
671                if(j == 0)
672                    scaled[t++] = '/';
673                else if (j == line -1)
674                    scaled[t++] = '\\';
675                else
676                    scaled[t++] = '|';
677            }
678            scaled[t++] = ' ';
679
680            for(i = 0; i < *max_width; i++)
681            {
682                scaled[t++] = ret[o++];
683            }
684            scaled[t++] = ' ';
685            if(think)
686            {
687                scaled[t++] = ')';
688            }
689            else
690            {
691                if(j == 0)
692                    scaled[t++] = '\\';
693                else if (j == line -1)
694                    scaled[t++] = '/';
695                else
696                    scaled[t++] = '|';
697            }
698            scaled[t++] = '\n';
699        }
700
701        scaled[t++] = ' ';
702        for(i = 0; i < *max_width+2; i++)
703            scaled[t++] = '-';
704        scaled[t++] = ' ';
705        scaled[t] = 0;
706
707        free(ret);
708        ret = NULL;
709        ret = scaled;
710    }
711    else
712    {
713        /* Put ballon */
714        char *scaled = malloc((size+4) * 3);
715        t = 0;
716        *max_width = size -1 ;
717        o = 0;
718        scaled[t++] = ' ';
719        for(i = 0; i < *max_width+2; i++)
720            scaled[t++] = '_';
721        scaled[t++] = ' ';
722        scaled[t++] = '\n';
723        if(think)
724            scaled[t++] = '(';
725        else
726            scaled[t++] = '<';
727        scaled[t++] = ' ';
728        for(i = 0; i < *max_width; i++)
729        {
730            scaled[t++] = ret[o++];
731        }
732        scaled[t++] = ' ';
733        if(think)
734            scaled[t++] = ')';
735        else
736            scaled[t++] = '>';
737
738        scaled[t++] = '\n';
739        scaled[t++] = ' ';
740        for(i = 0; i < *max_width+2; i++)
741            scaled[t++] = '-';
742
743        free(ret);
744        ret = NULL;
745        ret = scaled;
746    }
747
748
749    return ret;
750}
751
Note: See TracBrowser for help on using the repository browser.