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

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