#define SNOWFLAKE \ " _ 8* @ \n"\ " . O __ _| |_ __ ' * ' \n"\ " * /'v /\\_ + _/\\ v`\\ o \n"\ " > x \\ _| |_ / x < \n"\ " .0 __`./\\ _^_ /\\.'__ @ .: ' \n"\ " _\\ \\__/ /\\ v /\\ \\__/ /_ \n"\ "' |_ + __ < > < > __ + _| 0. \n"\ " /_/ \\ \\/_^_\\/ / \\_\\ . \n"\ " . @ .'\\/ _ v _ \\/`. * 8 \n"\ " > x / _| |_ \\ x < @ .\n"\ " . : \\.^_\\/_ + _\\/_^./ Oo * \n"\ " ' |_| \n"\ /* this software is she12ware * .o '. @ o. */ #define PAYPLAN "!!!PLEASE DONATE TO SDF.ORG!!!" #define DID_PAY 0 #define VERSION 1.0 #include <stdlib.h> #include <stdio.h> #include <string.h> #include <time.h> #include <unistd.h> #ifdef __unix__ #include <sys/ioctl.h> #define DECXY struct winsize win; #define GETXY ioctl(STDIN_FILENO,TIOCGWINSZ,&win)!=-1 #define GETXV win.ws_col #define GETYV win.ws_row #define ENVXV "COLUMNS" #define ENVYV "LINES" #define SEEDR srandom(time(NULL)) #define GETRA 32+random()%(126-32+1) #define GETRC(S) S[random()%strlen(S)] #define GETRN(B,F) B+random()%F #define CLEAR printf("\x1B[H\x1B[2J") #define SLEEP(T) usleep(T) #else #include <windows.h> #define DECXY CONSOLE_SCREEN_BUFFER_INFO win #define GETXY GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&win) #define GETXV win.srWindow.Right-win.srWindow.Left+1 #define GETYV win.srWindow.Bottom-win.srWindow.Top+1 #define ENVXV "COLS" #define ENVYV "ROWS" #define SEEDR srand(time(NULL)) #define RANDM rand() #define GETRA 32+rand()%(126-32+1) #define GETRC(S) S[rand()%strlen(S)] #define GETRN(B,F) B+rand()%F #define CLEAR system("cls") #define SLEEP(T) sleep(T/1000000) #endif char *init_string(char,long); char **init_strings(char,long,long); void read_strings(char*,char**,long,long); int main(int argc,char **argv){ int c,s; int cascade=0; int debug=0; int frame=0; int increase=0; int maximize=0; int randomize=0; int tail=0; int upwards=0; int wide=0; long h,w,x; long length; long density=750; long height=10; long iterations=-1; long swing=0; long timeout=140000; long width=53; char bg=' '; char *background=NULL; char *charset=NULL; char *frameset="--||+"; char *framebar_top; char *framebar_bot; char *intro="It'Snowtime!"; char *overlay=DID_PAY?NULL:PAYPLAN; char *snow=".*'.'*:oOO008@****...@"; char **buf; char **top; char **bot; while((c=getopt(argc,argv,"b:c:d:Df:Fh:i:Io:LRs:St:Tw:WUX"))!=-1) switch(c){ case'b':if(strlen(optarg)>1) background=optarg; else bg=*optarg;break; case'c':snow=optarg;break; case'd':density=strtol(optarg,NULL,0);break; case'f':frameset=optarg;break; case'h':height=strtol(optarg,NULL,0);break; case'i':iterations=strtol(optarg,NULL,0);break; case'o':overlay=optarg;break; case's':swing=strtol(optarg,NULL,0);break; case't':timeout=strtol(optarg,NULL,0);break; case'w':width=strtol(optarg,NULL,0);break; case'D':debug=1;break; case'F':frame=1;break; case'I':increase=1;break; case'L':cascade=1;break; case'R':cascade=2;break; case'S':randomize=1;break; case'T':tail=1;break; case'U':upwards=1;break; case'W':wide=1;break; case'X':maximize=1;break; default:printf("\n%s\nusage: %s [b:c:d:Df:Fh:i:Io:LRs:St:Tw:WUX]\n" "\t-b <c>[c*].....set background character, string or file\n" "\t-c <s>.........set flake charset string\n" "\t-d <ld>........set background density\n" "\t-f <cccc>[c]...set framebar characters: <top><bottom><left><right>[corner]\n" "\t-h <ld>........set height\n" "\t-i <ld>........set iterations\n" "\t-o <s>.........set overlay string or file\n" "\t-s <ld>........set flake swing range\n" "\t-t <ld>........set timeout in microseconds\n" "\t-w <ld>........set width\n" "\n" "\t-D.............show debug information\n" "\t-F.............draw frame\n" "\t-I.............increase density each iteration\n" "\t-L.............cascade to left\n" "\t-R.............cascade to right\n" "\t-S.............random parameters\n" "\t-T.............flakes draw tails\n" "\t-U.............flakes go upwards\n" "\t-W.............full width flakes\n" "\t-X.............maximize to current terminal size\n" ,SNOWFLAKE,*argv); return 1; } SEEDR; /* get terminal window size .8o .@ : o*. */ if(maximize){ DECXY; if(GETXY){ width=GETXV; height=GETYV; height-=debug*(5+strlen(snow)/width)+1; }else if(getenv(ENVXV)&&getenv(ENVYV)){ width=strtol(getenv(ENVXV),NULL,0); height=strtol(getenv(ENVYV),NULL,0); height-=debug*(5+strlen(snow)/width)+1; } } height=height>0?height:1; width=width>0?width:1; /* randomize parameters .0 : .*:. .' O' 0 */ if(randomize){ height=GETRN(1,height); width=GETRN(1,width); randomize=GETRN(1,10*height); bg=GETRA; background="/dev/urandom"; density=GETRN(10,randomize+10*height); swing=GETRN(0,height); timeout=GETRN(35000,900000-35000); increase=GETRN(0,2); cascade=GETRN(0,3); tail=GETRN(0,2); upwards=GETRN(0,2); wide=GETRN(0,2); frame=GETRN(0,2); frameset=init_string('\0',5); if(frame&&!frameset)return 1; for(w=0;w<5;w++) frameset[w]=GETRA; snow=init_string('\0',randomize); if(!snow)return 1; for(w=0;w<randomize;w++) snow[w]=GETRA; } /* create framebars . * .@*@* * 8 'O */ if(frame){ if(height>2&&width>2){ framebar_top=init_string(frameset[0],width); framebar_bot=init_string(frameset[1],width); if(!framebar_top||!framebar_bot)return 1; if(frameset[4]) framebar_top[0] =framebar_bot[0] =framebar_top[width-1] =framebar_bot[width-1] =frameset[4]; height-=2; width-=2; }else frame=0; } /* create background '*8 '. o . .* 0 */ bot=init_strings(bg,height,width); if(!bot)return 1; if(background) read_strings(background,bot,height,width); /* create snowerlay . * O.o. * .'* o */ top=init_strings(bg,height,width); if(!top)return 1; if(overlay) read_strings(overlay,top,height,width); /* create charset * ' * . O :. o0 8 */ charset=init_string('\0',density+strlen(snow)+2); if(!charset)return 1; memset(charset,bg,density); strcat(charset,snow); /* create buffer . 'o . *8 O * ' @. :*/ length=(cascade?width+height:width)+swing; buf=init_strings(bg,height,length); if(!buf)return 1; if(debug){ x=length/2-strlen(intro)/2; if(x>=0) memcpy(buf[height/2]+x,intro,strlen(intro)); } /* start of output . * * . . O. @' */ while(iterations>-1?iterations--:iterations!=0){ CLEAR; if(debug){ if(frame)putchar(' '); for(w=1;w<=width;w++) putchar(w%5?',':'|'); putchar('\n'); } if(frame)puts(framebar_top); /* snow row by row ' 8 . . @ *o * .*/ for(c=h=0;h<height;h++){ if(frame)putchar(frameset[2]); if(swing){ if(c==0||c==swing) s=c?0:1; s?c++:c--; if(swing>height) c=GETRN(1,height); } if(cascade) x=cascade+upwards==2?height-h:h; else x=0; /* snow flake by flake . @8 @* . 8 */ for(w=c+x;w<width+c+x;w++) if(top[h][w-c-x]!=bg) putchar(top[h][w-c-x]); else if(buf[h][wide?c+cascade:w]!=bg) putchar(buf[h][wide?c+cascade:w]); else putchar(bot[h][w-c-x]); if(frame)putchar(frameset[3]); putchar('\n'); } if(frame)puts(framebar_bot); if(debug) printf("height: %ld width: %ld round: %ld timeout: %ld\n" "cascade: %s swing: %d/%ld density: %ld increase: %d\n" "direction: %s tail: %s wide: %s random: %s\n" "background: '%c' frameset: '%s' charset: '%s'\n" ,height,width,iterations,timeout ,cascade?cascade<2?"left":"right":"no",c,swing,density,increase ,upwards?"up":"down",tail?"yes":"no",wide?"yes":"no",randomize?"yes":"no" ,bg,frameset,snow); /* end of output *. @ .8o O :' . */ if(increase&&density){ x=100; density=strlen(charset)-strlen(snow); increase=density?density>x?density/x:1:0; charset+=increase; } /* shift rows .O :'@ :. * 8 */ if(upwards){ for(h=0;h<height-1;h++) strncpy(buf[h],buf[h+1],length); c=h-1; x=0; }else{ for(--h;h;h--) strncpy(buf[h],buf[h-1],length); c=h+1; x=height/2; } /* recreate last row *' 0 0 * . @ */ for(w=0;w<length;w++) if((tail &&height>1) &&buf[c][w]!=bg &&buf[c][w]!=buf[GETRN(x,height/2)][w]) buf[h][w]=buf[c][w]; else if(w==0) buf[h][w]=GETRC(charset); else for(buf[h][w]=GETRC(charset); buf[h][w]==buf[h][w-1] &&buf[h][w]!=bg&&density>1; buf[h][w]=GETRC(charset)) ; SLEEP(timeout); } return 0; } /* allocate and fill char array * .0 * oO .*/ char *init_string(char bg,long width){ char *str=NULL; str=malloc(width+1); if(!str)return NULL; memset(str,'\0',width+1); memset(str,bg,width); return str; } /* allocate and fill 2D char array .o '* .@ */ char **init_strings(char bg,long height,long width){ long h; char **strs=NULL; strs=malloc(height*sizeof(*strs)); if(!strs)return NULL; for(h=0;h<height;h++){ strs[h]=malloc(width+1); if(!strs[h])return NULL; memset(strs[h],'\0',width+1); memset(strs[h],bg,width); } return strs; } /* read file or string and fill 2D char array .o@*/ void read_strings(char *input,char **strs,long height,long width){ long h,w; char c,*p; FILE *in=NULL; /* read input file . * 8o . :' ' @ */ if(strlen(input)==1&&*input=='-') in=stdin; else in=fopen(input,"r"); if(in){ input=init_string(' ',height*width); w=0; while((c=fgetc(in))!=EOF&&w<height*width) input[w++]=c; if(in!=stdin) fclose(in); } /* transfer ascii chars into 2D array *' 8 */ p=input; for(h=0;h<height;h++) for(w=0;w<width;w++) switch(c=*p++){ case'\0':h=height;w=width;break; case'\r': case'\n':w=width;break; case'\t':w+=3;break; default:if(c<32||c>126)break; strs[h][w]=c; } if(in)free(input); }